diff options
Diffstat (limited to 'upstream/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenEndpoint.java')
-rw-r--r-- | upstream/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenEndpoint.java | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/upstream/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenEndpoint.java b/upstream/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenEndpoint.java new file mode 100644 index 00000000..a456d702 --- /dev/null +++ b/upstream/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenEndpoint.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.sts; + +import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; +import static javax.servlet.http.HttpServletResponse.SC_CREATED; +import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; +import static javax.servlet.http.HttpServletResponse.SC_NOT_IMPLEMENTED; +import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT; +import static javax.servlet.http.HttpServletResponse.SC_OK; +import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.oltu.oauth2.as.issuer.OAuthIssuer; +import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl; +import org.apache.oltu.oauth2.as.issuer.UUIDValueGenerator; +import org.apache.oltu.oauth2.as.response.OAuthASResponse; +import org.apache.oltu.oauth2.common.OAuth; +import org.apache.oltu.oauth2.common.exception.OAuthProblemException; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.apache.oltu.oauth2.common.message.OAuthResponse; +import org.apache.oltu.oauth2.common.message.types.GrantType; +import org.apache.oltu.oauth2.common.message.types.TokenType; +import org.opendaylight.aaa.AuthenticationBuilder; +import org.opendaylight.aaa.ClaimBuilder; +import org.opendaylight.aaa.PasswordCredentialBuilder; +import org.opendaylight.aaa.api.Authentication; +import org.opendaylight.aaa.api.AuthenticationException; +import org.opendaylight.aaa.api.Claim; +import org.opendaylight.aaa.api.PasswordCredentials; + +/** + * Secure Token Service (STS) endpoint. + * + * @author liemmn + * + */ +public class TokenEndpoint extends HttpServlet { + private static final long serialVersionUID = 8272453849539659999L; + + private static final String DOMAIN_SCOPE_REQUIRED = "Domain scope required"; + private static final String NOT_IMPLEMENTED = "not_implemented"; + private static final String UNAUTHORIZED = "unauthorized"; + + static final String TOKEN_GRANT_ENDPOINT = "/token"; + static final String TOKEN_REVOKE_ENDPOINT = "/revoke"; + static final String TOKEN_VALIDATE_ENDPOINT = "/validate"; + + private transient OAuthIssuer oi; + + @Override + public void init(ServletConfig config) throws ServletException { + oi = new OAuthIssuerImpl(new UUIDValueGenerator()); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + try { + if (req.getServletPath().equals(TOKEN_GRANT_ENDPOINT)) { + createAccessToken(req, resp); + } else if (req.getServletPath().equals(TOKEN_REVOKE_ENDPOINT)) { + deleteAccessToken(req, resp); + } else if (req.getServletPath().equals(TOKEN_VALIDATE_ENDPOINT)) { + validateToken(req, resp); + } + } catch (AuthenticationException e) { + error(resp, SC_UNAUTHORIZED, e.getMessage()); + } catch (OAuthProblemException oe) { + error(resp, oe); + } catch (Exception e) { + error(resp, e); + } + } + + private void validateToken(HttpServletRequest req, HttpServletResponse resp) + throws IOException, OAuthSystemException { + String token = req.getReader().readLine(); + if (token != null) { + Authentication authn = ServiceLocator.getInstance().getTokenStore().get(token.trim()); + if (authn == null) { + throw new AuthenticationException(UNAUTHORIZED); + } else { + ServiceLocator.getInstance().getAuthenticationService().set(authn); + resp.setStatus(SC_OK); + } + } else { + throw new AuthenticationException(UNAUTHORIZED); + } + } + + // Delete an access token + private void deleteAccessToken(HttpServletRequest req, HttpServletResponse resp) + throws IOException { + String token = req.getReader().readLine(); + if (token != null) { + if (ServiceLocator.getInstance().getTokenStore().delete(token.trim())) { + resp.setStatus(SC_NO_CONTENT); + } else { + throw new AuthenticationException(UNAUTHORIZED); + } + } else { + throw new AuthenticationException(UNAUTHORIZED); + } + } + + // Create an access token + private void createAccessToken(HttpServletRequest req, HttpServletResponse resp) + throws OAuthSystemException, OAuthProblemException, IOException { + Claim claim = null; + String clientId = null; + + OAuthRequest oauthRequest = new OAuthRequest(req); + // Any client credentials? + clientId = oauthRequest.getClientId(); + if (clientId != null) { + ServiceLocator.getInstance().getClientService() + .validate(clientId, oauthRequest.getClientSecret()); + } + + // Credential request... + if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.PASSWORD.toString())) { + String domain = oauthRequest.getScopes().iterator().next(); + PasswordCredentials pc = new PasswordCredentialBuilder().setUserName( + oauthRequest.getUsername()).setPassword(oauthRequest.getPassword()) + .setDomain(domain).build(); + if (!oauthRequest.getScopes().isEmpty()) { + claim = ServiceLocator.getInstance().getCredentialAuth().authenticate(pc); + } + } else if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals( + GrantType.REFRESH_TOKEN.toString())) { + // Refresh token... + String token = oauthRequest.getRefreshToken(); + if (!oauthRequest.getScopes().isEmpty()) { + String domain = oauthRequest.getScopes().iterator().next(); + // Authenticate... + Authentication auth = ServiceLocator.getInstance().getTokenStore().get(token); + if (auth != null && domain != null) { + List<String> roles = ServiceLocator.getInstance().getIdmService() + .listRoles(auth.userId(), domain); + if (!roles.isEmpty()) { + ClaimBuilder cb = new ClaimBuilder(auth); + cb.setDomain(domain); // scope domain + // Add roles for the scoped domain + for (String role : roles) { + cb.addRole(role); + } + claim = cb.build(); + } + } + } else { + error(resp, SC_BAD_REQUEST, DOMAIN_SCOPE_REQUIRED); + } + } else { + // Support authorization code later... + error(resp, SC_NOT_IMPLEMENTED, NOT_IMPLEMENTED); + } + + // Respond with OAuth token + oauthAccessTokenResponse(resp, claim, clientId); + } + + // Build OAuth access token response from the given claim + private void oauthAccessTokenResponse(HttpServletResponse resp, Claim claim, String clientId) + throws OAuthSystemException, IOException { + if (claim == null) { + throw new AuthenticationException(UNAUTHORIZED); + } + String token = oi.accessToken(); + + // Cache this token... + Authentication auth = new AuthenticationBuilder(new ClaimBuilder(claim).setClientId( + clientId).build()).setExpiration(tokenExpiration()).build(); + ServiceLocator.getInstance().getTokenStore().put(token, auth); + + OAuthResponse r = OAuthASResponse.tokenResponse(SC_CREATED).setAccessToken(token) + .setTokenType(TokenType.BEARER.toString()) + .setExpiresIn(Long.toString(auth.expiration())) + .buildJSONMessage(); + write(resp, r); + } + + // Token expiration + private long tokenExpiration() { + return ServiceLocator.getInstance().getTokenStore().tokenExpiration(); + } + + // Emit an error OAuthResponse with the given HTTP code + private void error(HttpServletResponse resp, int httpCode, String error) { + try { + OAuthResponse r = OAuthResponse.errorResponse(httpCode).setError(error) + .buildJSONMessage(); + write(resp, r); + } catch (Exception e1) { + // Nothing to do here + } + } + + // Emit an error OAuthResponse for the given OAuth-related exception + private void error(HttpServletResponse resp, OAuthProblemException e) { + try { + OAuthResponse r = OAuthResponse.errorResponse(SC_BAD_REQUEST).error(e) + .buildJSONMessage(); + write(resp, r); + } catch (Exception e1) { + // Nothing to do here + } + } + + // Emit an error OAuthResponse for the given generic exception + private void error(HttpServletResponse resp, Exception e) { + try { + OAuthResponse r = OAuthResponse.errorResponse(SC_INTERNAL_SERVER_ERROR) + .setError(e.getClass().getName()) + .setErrorDescription(e.getMessage()).buildJSONMessage(); + write(resp, r); + } catch (Exception e1) { + // Nothing to do here + } + } + + // Write out an OAuthResponse + private void write(HttpServletResponse resp, OAuthResponse r) throws IOException { + resp.setStatus(r.getResponseStatus()); + PrintWriter pw = resp.getWriter(); + pw.print(r.getBody()); + pw.flush(); + pw.close(); + } +} |