Skip to content

Instantly share code, notes, and snippets.

@ziodave
Last active August 29, 2015 14:04
Show Gist options
  • Save ziodave/cfb77767207694a74351 to your computer and use it in GitHub Desktop.
Save ziodave/cfb77767207694a74351 to your computer and use it in GitHub Desktop.
Spring Security : WordPress Authentication Filter (a draft)
package io.insideout.chat.security;
import io.insideout.chat.domain.WordPressUser;
import io.insideout.chat.services.WordPressAuthenticationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.stereotype.Service;
import java.util.Collection;
/**
* Authenticate users using WordPress and one-time passwords.
*/
@Service
public class WordPressAuthenticationProvider implements AuthenticationProvider {
@Autowired
private WordPressAuthenticationService wordPressAuthenticationService;
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
final UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
// Get the username and password.
final String[] name = token.getName().split("@");
// If the username doesn't have an application key or the application key is empty, then we can't authenticate.
if (2 > name.length || name[1].isEmpty() || null == token.getCredentials()) {
logger.warn("WordPress authentication can't continue [ username :: {} ][ credentials :: {} ]", name[0], token.getCredentials());
return null;
}
// Get the password.
final String otp = token.getCredentials().toString();
logger.debug("[ username :: {} ][ key :: {} ][ otp :: {} ]", name[0], name[1], otp);
final WordPressUser user;
try {
user = wordPressAuthenticationService.authenticate(name[0], name[1], otp);
} catch (final Exception e) {
logger.error("Authentication failed [ exception :: {} ][ message :: {} ]", e.getClass().getName(), e.getMessage());
return null;
}
// Prepare the authorities.
final Collection<GrantedAuthority> roles = AuthorityUtils.createAuthorityList(user.getRoles());
// Return the token.
return new UsernamePasswordAuthenticationToken(user, null, roles);
}
/**
* We support the standard username/password authentication token. We expect it to be something like:
* user@app-key:one-time-key
*
* @param authentication The authentication token class.
* @return True if it's *UsernamePasswordAuthenticationToken* otherwise false.
*/
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
package io.insideout.chat.services;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.insideout.chat.domain.App;
import io.insideout.chat.domain.WordPressUser;
import io.insideout.chat.exceptions.AppNotFoundException;
import io.insideout.chat.exceptions.WordPressAuthenticationFailedException;
import org.apache.http.Consts;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Provide functions to authenticate users using a WordPress end-point.
*/
@Service
public class WordPressAuthenticationService {
@Autowired
private AppService appService;
@Autowired
private ObjectMapper objectMapper;
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* Authenticate the user using the provided data.
*
* @param username The username.
* @param appKey The application key.
* @param otp The one-time password.
*/
public WordPressUser authenticate(final String username, final String appKey, final String otp) throws AppNotFoundException, IOException, WordPressAuthenticationFailedException {
logger.debug("[ username :: {} ][ app-key :: {} ][ otp :: {} ]", username, appKey, otp);
final App app = appService.getByKey(appKey);
final String url = app.getEndPoint();
// Even if Fluent API will be easier, it's not a Spring Boot managed package, so let's go with the HttpClient.
// Create the POST data.
final List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("username", username));
params.add(new BasicNameValuePair("otp", otp));
final UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, Consts.UTF_8);
logger.debug("[ url :: {} ][ username :: {} ][ otp :: {} ]", url, username, otp);
// Create the POST request.
final HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(entity);
// Create the client and execute.
final CloseableHttpClient httpClient = HttpClients.createDefault();
final CloseableHttpResponse response = httpClient.execute(httpPost);
// Get the response from the remote server.
final int statusCode;
final String content;
try {
statusCode = response.getStatusLine().getStatusCode();
content = EntityUtils.toString(response.getEntity(), "UTF-8");
} finally {
response.close();
}
// If the status code is not 200, throw an exception.
if (200 != statusCode) {
logger.debug("Authentication failed [ status-code :: {} ]", statusCode);
throw new WordPressAuthenticationFailedException();
}
// Decode the JSON response.
final WordPressUser user = objectMapper.readValue(content, WordPressUser.class);
logger.debug("Authentication succeeded [ username :: {} ][ user :: {} ]", username, user);
return user;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment