diff options
Diffstat (limited to 'upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealm.java')
-rw-r--r-- | upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealm.java | 369 |
1 files changed, 0 insertions, 369 deletions
diff --git a/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealm.java b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealm.java deleted file mode 100644 index f9ae5051..00000000 --- a/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealm.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 2015 Brocade Communications Systems, Inc. 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.shiro.realm; - -import com.google.common.base.Strings; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.shiro.authc.AuthenticationException; -import org.apache.shiro.authc.AuthenticationInfo; -import org.apache.shiro.authc.AuthenticationToken; -import org.apache.shiro.authc.SimpleAuthenticationInfo; -import org.apache.shiro.authc.UsernamePasswordToken; -import org.apache.shiro.authz.AuthorizationInfo; -import org.apache.shiro.authz.SimpleAuthorizationInfo; -import org.apache.shiro.codec.Base64; -import org.apache.shiro.realm.AuthorizingRealm; -import org.apache.shiro.subject.PrincipalCollection; -import org.opendaylight.aaa.api.Authentication; -import org.opendaylight.aaa.api.TokenAuth; -import org.opendaylight.aaa.basic.HttpBasicAuth; -import org.opendaylight.aaa.sts.ServiceLocator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * TokenAuthRealm is an adapter between the AAA shiro subsystem and the existing - * <code>TokenAuth</code> mechanisms. Thus, one can enable use of - * <code>IDMStore</code> and <code>IDMMDSALStore</code>. - * - * @author Ryan Goulding (ryandgoulding@gmail.com) - */ -public class TokenAuthRealm extends AuthorizingRealm { - - private static final String USERNAME_DOMAIN_SEPARATOR = "@"; - - /** - * The unique identifying name for <code>TokenAuthRealm</code> - */ - private static final String TOKEN_AUTH_REALM_DEFAULT_NAME = "TokenAuthRealm"; - - /** - * The message that is displayed if no <code>TokenAuth</code> interface is - * available yet - */ - private static final String AUTHENTICATION_SERVICE_UNAVAILABLE_MESSAGE = "{\"error\":\"Authentication service unavailable\"}"; - - /** - * The message that is displayed if credentials are missing or malformed - */ - private static final String FATAL_ERROR_DECODING_CREDENTIALS = "{\"error\":\"Unable to decode credentials\"}"; - - /** - * The message that is displayed if non-Basic Auth is attempted - */ - private static final String FATAL_ERROR_BASIC_AUTH_ONLY = "{\"error\":\"Only basic authentication is supported by TokenAuthRealm\"}"; - - /** - * The purposefully generic message displayed if <code>TokenAuth</code> is - * unable to validate the given credentials - */ - private static final String UNABLE_TO_AUTHENTICATE = "{\"error\":\"Could not authenticate\"}"; - - private static final Logger LOG = LoggerFactory.getLogger(TokenAuthRealm.class); - - public TokenAuthRealm() { - super(); - super.setName(TOKEN_AUTH_REALM_DEFAULT_NAME); - } - - /* - * (non-Javadoc) - * - * Roles are derived from <code>TokenAuth.authenticate()</code>. Shiro roles - * are identical to existing IDM roles. - * - * @see - * org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache - * .shiro.subject.PrincipalCollection) - */ - @Override - protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { - final Object primaryPrincipal = principalCollection.getPrimaryPrincipal(); - final ODLPrincipal odlPrincipal; - try { - odlPrincipal = (ODLPrincipal) primaryPrincipal; - return new SimpleAuthorizationInfo(odlPrincipal.getRoles()); - } catch(ClassCastException e) { - LOG.error("Couldn't decode authorization request", e); - } - return new SimpleAuthorizationInfo(); - } - - /** - * Bridge new to old style <code>TokenAuth</code> interface. - * - * @param username The request username - * @param password The request password - * @param domain The request domain - * @return <code>username:password:domain</code> - */ - static String getUsernamePasswordDomainString(final String username, final String password, - final String domain) { - return username + HttpBasicAuth.AUTH_SEP + password + HttpBasicAuth.AUTH_SEP + domain; - } - - /** - * - * @param credentialToken - * @return Base64 encoded token - */ - static String getEncodedToken(final String credentialToken) { - return Base64.encodeToString(credentialToken.getBytes()); - } - - /** - * - * @param encodedToken - * @return Basic <code>encodedToken</code> - */ - static String getTokenAuthHeader(final String encodedToken) { - return HttpBasicAuth.BASIC_PREFIX + encodedToken; - } - - /** - * - * @param tokenAuthHeader - * @return a map with the basic auth header - */ - Map<String, List<String>> formHeadersWithToken(final String tokenAuthHeader) { - final Map<String, List<String>> headers = new HashMap<String, List<String>>(); - final List<String> headerValue = new ArrayList<String>(); - headerValue.add(tokenAuthHeader); - headers.put(HttpBasicAuth.AUTH_HEADER, headerValue); - return headers; - } - - /** - * Adapter between basic authentication mechanism and existing - * <code>TokenAuth</code> interface. - * - * @param username Username from the request - * @param password Password from the request - * @param domain Domain from the request - * @return input map for <code>TokenAuth.validate()</code> - */ - Map<String, List<String>> formHeaders(final String username, final String password, - final String domain) { - String usernamePasswordToken = getUsernamePasswordDomainString(username, password, domain); - String encodedToken = getEncodedToken(usernamePasswordToken); - String tokenAuthHeader = getTokenAuthHeader(encodedToken); - return formHeadersWithToken(tokenAuthHeader); - } - - /** - * Adapter to check for available <code>TokenAuth<code> implementations. - * - * @return - */ - boolean isTokenAuthAvailable() { - return ServiceLocator.getInstance().getAuthenticationService() != null; - } - - /* - * (non-Javadoc) - * - * Authenticates against any <code>TokenAuth</code> registered with the - * <code>ServiceLocator</code> - * - * @see - * org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org - * .apache.shiro.authc.AuthenticationToken) - */ - @Override - protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) - throws AuthenticationException { - - String username = ""; - String password = ""; - String domain = HttpBasicAuth.DEFAULT_DOMAIN; - - try { - final String qualifiedUser = extractUsername(authenticationToken); - if (qualifiedUser.contains(USERNAME_DOMAIN_SEPARATOR)) { - final String [] qualifiedUserArray = qualifiedUser.split(USERNAME_DOMAIN_SEPARATOR); - try { - username = qualifiedUserArray[0]; - domain = qualifiedUserArray[1]; - } catch (ArrayIndexOutOfBoundsException e) { - LOG.trace("Couldn't parse domain from {}; trying without one", - qualifiedUser, e); - } - } else { - username = qualifiedUser; - } - password = extractPassword(authenticationToken); - - } catch (NullPointerException e) { - throw new AuthenticationException(FATAL_ERROR_DECODING_CREDENTIALS, e); - } catch (ClassCastException e) { - throw new AuthenticationException(FATAL_ERROR_BASIC_AUTH_ONLY, e); - } - - // check to see if there are TokenAuth implementations available - if (!isTokenAuthAvailable()) { - throw new AuthenticationException(AUTHENTICATION_SERVICE_UNAVAILABLE_MESSAGE); - } - - // if the password is empty, this is an OAuth2 request, not a Basic HTTP - // Auth request - if (!Strings.isNullOrEmpty(password)) { - if (ServiceLocator.getInstance().getAuthenticationService().isAuthEnabled()) { - Map<String, List<String>> headers = formHeaders(username, password, domain); - // iterate over <code>TokenAuth</code> implementations and - // attempt to - // authentication with each one - final List<TokenAuth> tokenAuthCollection = ServiceLocator.getInstance() - .getTokenAuthCollection(); - for (TokenAuth ta : tokenAuthCollection) { - try { - LOG.debug("Authentication attempt using {}", ta.getClass().getName()); - final Authentication auth = ta.validate(headers); - if (auth != null) { - LOG.debug("Authentication attempt successful"); - ServiceLocator.getInstance().getAuthenticationService().set(auth); - final ODLPrincipal odlPrincipal = ODLPrincipal.createODLPrincipal(auth); - return new SimpleAuthenticationInfo(odlPrincipal, password.toCharArray(), - getName()); - } - } catch (AuthenticationException ae) { - LOG.debug("Authentication attempt unsuccessful"); - throw new AuthenticationException(UNABLE_TO_AUTHENTICATE, ae); - } - } - } - } - - // extract the authentication token and attempt validation of the token - final String token = extractUsername(authenticationToken); - final Authentication auth; - try { - auth = validate(token); - if (auth != null) { - final ODLPrincipal odlPrincipal = ODLPrincipal.createODLPrincipal(auth); - return new SimpleAuthenticationInfo(odlPrincipal, "", getName()); - } - } catch (AuthenticationException e) { - LOG.debug("Unknown OAuth2 Token Access Request", e); - } - - LOG.debug("Authentication failed: exhausted TokenAuth resources"); - return null; - } - - private Authentication validate(final String token) { - Authentication auth = ServiceLocator.getInstance().getTokenStore().get(token); - if (auth == null) { - throw new AuthenticationException("Could not validate the token " + token); - } else { - ServiceLocator.getInstance().getAuthenticationService().set(auth); - } - return auth; - } - - /** - * extract the username from an <code>AuthenticationToken</code> - * - * @param authenticationToken - * @return - * @throws ClassCastException - * @throws NullPointerException - */ - static String extractUsername(final AuthenticationToken authenticationToken) - throws ClassCastException, NullPointerException { - - return (String) authenticationToken.getPrincipal(); - } - - /** - * extract the password from an <code>AuthenticationToken</code> - * - * @param authenticationToken - * @return - * @throws ClassCastException - * @throws NullPointerException - */ - static String extractPassword(final AuthenticationToken authenticationToken) - throws ClassCastException, NullPointerException { - - final UsernamePasswordToken upt = (UsernamePasswordToken) authenticationToken; - return new String(upt.getPassword()); - } - - /** - * Since <code>TokenAuthRealm</code> is an <code>AuthorizingRealm</code>, it supports - * individual steps for authentication and authorization. In ODL's existing <code>TokenAuth</code> - * mechanism, authentication and authorization are currently done in a single monolithic step. - * <code>ODLPrincipal</code> is abstracted as a DTO between the two steps. It fulfills the - * responsibility of a <code>Principal</code>, since it contains identification information - * but no credential information. - * - * @author Ryan Goulding (ryandgoulding@gmail.com) - */ - private static class ODLPrincipal { - - private final String username; - private final String domain; - private final String userId; - private final Set<String> roles; - - private ODLPrincipal(final String username, final String domain, final String userId, final Set<String> roles) { - this.username = username; - this.domain = domain; - this.userId = userId; - this.roles = roles; - } - - /** - * A static factory method to create <code>ODLPrincipal</code> instances. - * - * @param username The authenticated user - * @param domain The domain <code>username</code> belongs to. - * @param userId The unique key for <code>username</code> - * @param roles The roles associated with <code>username</code>@<code>domain</code> - * @return A Principal for the given session; essentially a DTO. - */ - static ODLPrincipal createODLPrincipal(final String username, final String domain, - final String userId, final Set<String> roles) { - - return new ODLPrincipal(username, domain, userId, roles); - } - - /** - * A static factory method to create <code>ODLPrincipal</code> instances. - * - * @param auth Contains identifying information for the particular request. - * @return A Principal for the given session; essentially a DTO. - */ - static ODLPrincipal createODLPrincipal(final Authentication auth) { - return createODLPrincipal(auth.user(), auth.domain(), auth.userId(), auth.roles()); - } - - String getUsername() { - return this.username; - } - - String getDomain() { - return this.domain; - } - - String getUserId() { - return this.userId; - } - - Set<String> getRoles() { - return this.roles; - } - } -} |