Last active
August 29, 2015 14:04
-
-
Save ziodave/cfb77767207694a74351 to your computer and use it in GitHub Desktop.
Spring Security : WordPress Authentication Filter (a draft)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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