
de.adorsys.oauth.client.undertow.OAuthAuthenticationMechanism Maven / Gradle / Ivy
package de.adorsys.oauth.client.undertow;
import com.nimbusds.oauth2.sdk.AccessTokenResponse;
import com.nimbusds.oauth2.sdk.token.AccessToken;
import com.nimbusds.oauth2.sdk.token.Tokens;
import com.nimbusds.openid.connect.sdk.claims.UserInfo;
import de.adorsys.oauth.client.protocol.OAuthProtocol;
import de.adorsys.oauth.client.protocol.UserInfoResolver;
import io.undertow.security.api.AuthenticationMechanism;
import io.undertow.security.api.AuthenticationMechanismFactory;
import io.undertow.security.api.SecurityContext;
import io.undertow.security.idm.Account;
import io.undertow.security.idm.IdentityManager;
import io.undertow.security.idm.PasswordCredential;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.form.FormParserFactory;
import io.undertow.servlet.handlers.ServletRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URI;
import java.security.Principal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* OAuthAuthenticationMechanism
*/
@SuppressWarnings("unused")
public class OAuthAuthenticationMechanism implements AuthenticationMechanism {
private static final Logger LOG = LoggerFactory.getLogger(OAuthAuthenticationMechanism.class);
private OAuthProtocol oauthProtocol;
private UserInfoResolver userInfoResolver;
private boolean supportAuthCode;
private boolean supportGuest;
private boolean supportHttpSession;
private String mechanismName;
public OAuthAuthenticationMechanism(String mechanismName, Map properties) {
this.mechanismName = mechanismName;
oauthProtocol = OAuthProtocol.from(properties);
userInfoResolver = UserInfoResolver.from(properties);
supportAuthCode = extract(properties, "supportAuthCode", true);
supportGuest = extract(properties, "supportGuest", false);
supportHttpSession = extract(properties, "supportHttpSession", false);
LOG.info("use {} {}", oauthProtocol, userInfoResolver);
}
private boolean extract(Map properties, String key, boolean defaultValue) {
return properties.containsKey(key) ? Boolean.valueOf(properties.get(key)) : defaultValue;
}
@Override
public AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, SecurityContext securityContext) {
ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
HttpServletRequest request = servletRequestContext.getOriginalRequest();
HttpServletResponse response = servletRequestContext.getOriginalResponse();
Principal principal = request.getUserPrincipal();
if (principal != null) {
return AuthenticationMechanismOutcome.AUTHENTICATED;
}
URI requestURI = oauthProtocol.extractURI(request);
LOG.debug("Request " + requestURI);
// 1. check for token
AccessToken accessToken = oauthProtocol.resolveAccessToken(request);
// 1.1 kein accessToken and guest allowed
if (accessToken == null && supportGuest) {
Account account = securityContext.getIdentityManager().verify("guest", new PasswordCredential("NONE".toCharArray()));
securityContext.authenticationComplete(account, mechanismName, false);
return AuthenticationMechanismOutcome.AUTHENTICATED;
}
// try to authenticate with accessToken
if (authenticate(securityContext, accessToken, request, response)) {
return AuthenticationMechanismOutcome.AUTHENTICATED;
}
// return 401 if AuthorizationCodeFlow disallowed
if (!supportAuthCode) {
response.setStatus(401);
return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
}
// 2. run AuthorizationCodeFlow
AccessTokenResponse accessTokenResponse = oauthProtocol.runAuthorizationCodeFlow(requestURI);
if (accessTokenResponse != null && accessTokenResponse.getTokens() != null) {
Tokens tokens = accessTokenResponse.getTokens();
accessToken = tokens.getAccessToken(); //TODO refresh_token, login_session "supportHttpSession"
if (authenticate(securityContext, accessToken, request, response)) {
return AuthenticationMechanismOutcome.AUTHENTICATED;
}
}
// 3. redirect to authEndpoint to gain authCode
oauthProtocol.doAuthorizationRequest(response, requestURI);
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
}
/**
* authenticate with accessToken
*/
private boolean authenticate(SecurityContext securityContext, AccessToken accessToken, HttpServletRequest request, HttpServletResponse response) {
if (accessToken == null) {
return false;
}
LOG.debug("authenticate with accessToken {}", accessToken);
UserInfo userInfo = userInfoResolver.resolve(accessToken);
if (userInfo == null) {
LOG.trace("no userInfo available for {}", accessToken.getValue());
return false;
}
IdentityManager identityManager = securityContext.getIdentityManager();
// use the request to provide userinfo in loginmodules
request.setAttribute(UserInfo.class.getName(), userInfo);
Account account = identityManager.verify(userInfo.getSubject().getValue(), new PasswordCredential(accessToken.getValue().toCharArray()));
if (account == null) {
if (!supportGuest) {
LOG.error("no account created for {} {}, OAuthLoginModule configured correctly ?", userInfo.getSubject().getValue(), accessToken.getValue());
}
return false;
}
securityContext.authenticationComplete(account, mechanismName, supportHttpSession);
response.setHeader("Authorization", accessToken.toAuthorizationHeader());
return true;
}
@Override
public ChallengeResult sendChallenge(HttpServerExchange exchange, SecurityContext securityContext) {
return new ChallengeResult(false);
}
/**
* Factory
*/
public static final class Factory implements AuthenticationMechanismFactory {
private Map contextProperties;
public Factory(ServletContext servletContext) {
contextProperties = new HashMap<>();
Enumeration attrNames = servletContext.getInitParameterNames();
while (attrNames.hasMoreElements()) {
String key = attrNames.nextElement();
contextProperties.put(key, servletContext.getInitParameter(key));
}
LOG.info("initialize OAuthAuthenticationMechanism for {}", servletContext.getContextPath());
}
@Override
public AuthenticationMechanism create(String mechanismName, FormParserFactory formParserFactory, Map properties) {
properties.putAll(contextProperties);
return new OAuthAuthenticationMechanism(mechanismName, properties);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy