Eliminate AAA OAuth2 Provider 22/72022/14
authorRyan Goulding <ryandgoulding@gmail.com>
Tue, 15 May 2018 16:24:38 +0000 (12:24 -0400)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 18 Mar 2019 12:29:46 +0000 (13:29 +0100)
For the foreseeable past, OpenDaylight AAA development team has
agreed to avoid becoming an IdP.  The simple fact is that there
hundreds (if not more) of IdP solutions that are very secure and
have been proved with time.  The cost of maintaining an IdP is
extremely high, as the code is not always simple, and requires
highly skilled, security minded developers to maintain.

However, one remenant of IdP currently exists as a part of ODL
AAA, namely the OAuth2 Provider Implementation.  The OAuth2
Provider implementation allows users to derive scoped access
tokens in order to access the controller without using plain
credentials.  Part of OAuth2 inherently also provides easy
revocation of tokens.

However, this begs the question, are we an IdP at this point?
The preferred security model would be to delegate to an external,
third-party OAuth2 Provider, since many exist and are readily
available for federation.  This would limit the scope to
client-only for AAA.  This is preferred since AAA should not
be responsible for generation and revocation of tokens.  The
existing implementation utilized Apache OLTU, which has now
been retired to the Attic.

This patch favors removing unmaintained, possibly vulnerable
security code over maintaining OAuth2 backwards compatibility.
The functionality is not being replaced for two reasons:

1) we strive not to act as and IdP
2) most other OAuth2 provider solutions are spring-security based,
and are fairly difficult to use from non-spring contexts.

JIRA: AAA-173
Change-Id: I090014771b2f345cedc0330738b15b18684e1fcf
Signed-off-by: Ryan Goulding <ryandgoulding@gmail.com>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
aaa-shiro/impl/pom.xml
aaa-shiro/impl/src/main/java/org/opendaylight/aaa/AAAShiroProvider.java
aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java [deleted file]
aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/AnonymousPasswordValidator.java [deleted file]
aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/AnonymousRefreshTokenValidator.java [deleted file]
aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/OAuth2TokenServlet.java [deleted file]
aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/OAuthRequest.java [deleted file]
aaa-shiro/impl/src/test/java/org/opendaylight/aaa/shiro/oauth2/OAuth2TokenServletTest.java [deleted file]
features/odl-aaa-shiro/pom.xml
parent/pom.xml

index d9756f0268e8f0a3b42b422887e003f888f51989..512b2f876839a9b2a4e0eca9618b652935855aaf 100644 (file)
@@ -35,15 +35,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <artifactId>jersey-client</artifactId>
             <scope>provided</scope>
         </dependency>
-        <!-- OAuth2 dependencies for moon -->
-        <dependency>
-            <groupId>org.apache.oltu.oauth2</groupId>
-            <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.oltu.oauth2</groupId>
-            <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
-        </dependency>
         <dependency>
             <groupId>org.opendaylight.aaa</groupId>
             <artifactId>aaa-cert</artifactId>
index eade84615ac309cf5f833b919beda909cccd4cdf..fd18d94d9ee63f09b41981f810097111783f1832 100644 (file)
@@ -14,15 +14,12 @@ import org.opendaylight.aaa.api.AuthenticationService;
 import org.opendaylight.aaa.api.CredentialAuth;
 import org.opendaylight.aaa.api.IDMStoreException;
 import org.opendaylight.aaa.api.IIDMStore;
-import org.opendaylight.aaa.api.IdMService;
-import org.opendaylight.aaa.api.IdMServiceImpl;
 import org.opendaylight.aaa.api.PasswordCredentials;
 import org.opendaylight.aaa.api.StoreBuilder;
 import org.opendaylight.aaa.api.TokenStore;
 import org.opendaylight.aaa.api.password.service.PasswordHashService;
 import org.opendaylight.aaa.cert.api.ICertificateManager;
 import org.opendaylight.aaa.datastore.h2.H2TokenStore;
-import org.opendaylight.aaa.shiro.oauth2.OAuth2TokenServlet;
 import org.opendaylight.aaa.shiro.tokenauthrealm.auth.HttpBasicAuth;
 import org.opendaylight.aaa.shiro.tokenauthrealm.auth.TokenAuthenticators;
 import org.opendaylight.mdsal.binding.api.DataBroker;
@@ -91,7 +88,7 @@ public final class AAAShiroProvider {
         tokenAuthenticators = buildTokenAuthenticators(credentialAuth);
 
         try {
-            this.registerServletContexts(credentialAuth, authenticationService, iidmStore);
+            this.registerServletContexts();
         } catch (final ServletException | NamespaceException e) {
             LOG.warn("Could not initialize AAA servlet endpoints", e);
         }
@@ -103,18 +100,13 @@ public final class AAAShiroProvider {
         return new TokenAuthenticators(new HttpBasicAuth(credentialAuth));
     }
 
-    private void registerServletContexts(final CredentialAuth<PasswordCredentials> credentialAuth,
-            AuthenticationService authService, IIDMStore iidmStore) throws ServletException, NamespaceException {
-        LOG.info("attempting registration of AAA moon, oauth2 and auth servlets");
+    private void registerServletContexts() throws ServletException, NamespaceException {
+        LOG.info("attempting registration of AAA moon servlet");
 
         Preconditions.checkNotNull(httpService, "httpService cannot be null");
 
-        final IdMService idmService = new IdMServiceImpl(iidmStore);
-
         httpService.registerServlet(moonEndpointPath, new org.opendaylight.aaa.shiro.moon.MoonTokenEndpoint(),
                 null, null);
-        httpService.registerServlet(oauth2EndpointPath, new OAuth2TokenServlet(credentialAuth, authService,
-                tokenStore, idmService), null, null);
     }
 
     private static void initializeIIDMStore(final IIDMStore iidmStore) {
diff --git a/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java b/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java
deleted file mode 100644 (file)
index c701b07..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (c) 2016 Orange 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.filters;
-
-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_UNAUTHORIZED;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.oltu.oauth2.as.response.OAuthASResponse;
-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.TokenType;
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authc.AuthenticationException;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.UsernamePasswordToken;
-import org.apache.shiro.subject.Subject;
-import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
-import org.opendaylight.aaa.api.Authentication;
-import org.opendaylight.aaa.api.Claim;
-import org.opendaylight.aaa.api.TokenStore;
-import org.opendaylight.aaa.shiro.moon.MoonPrincipal;
-import org.opendaylight.aaa.shiro.oauth2.OAuthRequest;
-import org.opendaylight.aaa.shiro.tokenauthrealm.auth.AuthenticationBuilder;
-import org.opendaylight.aaa.shiro.tokenauthrealm.auth.ClaimBuilder;
-import org.opendaylight.aaa.shiro.web.env.ThreadLocals;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * MoonOAuthFilter filters oauth1 requests form token based authentication.
- *
- * @author Alioune BA alioune.ba@orange.com
- */
-public class MoonOAuthFilter extends AuthenticatingFilter {
-
-    private static final Logger LOG = LoggerFactory.getLogger(MoonOAuthFilter.class);
-
-    private static final String UNAUTHORIZED = "unauthorized";
-    private static final String UNAUTHORIZED_CREDENTIALS = "Unauthorized: Login/Password incorrect";
-
-    static final String TOKEN_GRANT_ENDPOINT = "/token";
-    static final String TOKEN_REVOKE_ENDPOINT = "/revoke";
-    static final String TOKEN_VALIDATE_ENDPOINT = "/validate";
-
-    private final TokenStore tokenStore;
-
-    public MoonOAuthFilter() {
-        tokenStore = ThreadLocals.TOKEN_STORE_TL.get();
-    }
-
-    @Override
-    protected UsernamePasswordToken createToken(final ServletRequest request,
-                                                final ServletResponse response) throws Exception {
-        final HttpServletRequest httpRequest;
-        final OAuthRequest oauthRequest;
-        try {
-            httpRequest = (HttpServletRequest) request;
-            oauthRequest = new OAuthRequest(httpRequest);
-        } catch (final ClassCastException e) {
-            LOG.debug("createToken() failed since the request could not be cast appropriately", e);
-            throw e;
-        }
-        return new UsernamePasswordToken(oauthRequest.getUsername(), oauthRequest.getPassword());
-    }
-
-    @Override
-    protected boolean onAccessDenied(final ServletRequest request, final ServletResponse response) throws Exception {
-        SecurityUtils.getSubject();
-        return executeLogin(request, response);
-    }
-
-    @Override
-    protected boolean onLoginSuccess(final AuthenticationToken token, final Subject subject,
-                                     final ServletRequest request, final ServletResponse response) throws Exception {
-
-        final HttpServletResponse httpResponse;
-        try {
-            httpResponse = (HttpServletResponse) response;
-        } catch (final ClassCastException e) {
-            LOG.debug("onLoginSuccess() failed since the response could not be cast appropriately", e);
-            throw e;
-        }
-
-        final MoonPrincipal principal;
-        try {
-            principal = (MoonPrincipal) subject.getPrincipals().getPrimaryPrincipal();
-        } catch (final ClassCastException e) {
-            LOG.debug("onLoginSuccess() failed since the subject could not be cast appropriately", e);
-            throw e;
-        }
-
-        final Claim claim = principal.principalToClaim();
-        oauthAccessTokenResponse(httpResponse, claim, "", principal.getToken());
-        return true;
-    }
-
-    @Override
-    protected boolean onLoginFailure(final AuthenticationToken token,
-                                     final AuthenticationException authenticationException,
-                                     final ServletRequest request, final ServletResponse response) {
-
-        final HttpServletResponse resp;
-        try {
-            resp = (HttpServletResponse) response;
-            error(resp, SC_BAD_REQUEST, UNAUTHORIZED_CREDENTIALS);
-        } catch (final ClassCastException cce) {
-            LOG.warn("onLoginFailure() failed since the response could not be cast appropriately", cce);
-        }
-
-        return false;
-    }
-
-    @Override
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    protected boolean executeLogin(final ServletRequest request, final ServletResponse response) throws Exception {
-
-        final HttpServletRequest req;
-        try {
-            req = (HttpServletRequest) request;
-        } catch (final ClassCastException e) {
-            LOG.debug("executeLogin() failed since the request could not be cast appropriately", e);
-            throw e;
-        }
-
-        final HttpServletResponse resp;
-        try {
-            resp = (HttpServletResponse) response;
-        } catch (final ClassCastException e) {
-            LOG.debug("executeLogin() failed since the request could not be cast apprioately", e);
-            throw e;
-        }
-
-        try {
-            if (req.getServletPath().equals(TOKEN_GRANT_ENDPOINT)) {
-                final UsernamePasswordToken token = createToken(request, response);
-                if (token == null) {
-                    final String msg = "A valid non-null AuthenticationToken "
-                            + "must be created in order to execute a login attempt.";
-                    throw new IllegalStateException(msg);
-                }
-                try {
-                    final Subject subject = getSubject(request, response);
-                    subject.login(token);
-                    return onLoginSuccess(token, subject, request, response);
-                } catch (final AuthenticationException e) {
-                    return onLoginFailure(token, e, request, response);
-                }
-            } /*else if (req.getServletPath().equals(TOKEN_REVOKE_ENDPOINT)) {
-                //TODO: deleteAccessToken(req, resp);
-            } else if (req.getServletPath().equals(TOKEN_VALIDATE_ENDPOINT)) {
-                //TODO: validateToken(req, resp);
-            }*/
-        } catch (final AuthenticationException e) {
-            error(resp, SC_UNAUTHORIZED, e.getMessage());
-        } catch (final OAuthProblemException oe) {
-            error(resp, oe);
-        } catch (final RuntimeException e) {
-            error(resp, e);
-        }
-        return false;
-    }
-
-    private void oauthAccessTokenResponse(final HttpServletResponse resp, final Claim claim, final String clientId,
-                                          final String token) throws OAuthSystemException, IOException {
-
-        if (claim == null) {
-            throw new AuthenticationException(UNAUTHORIZED);
-        }
-
-        // Cache this token...
-        final Authentication auth = new AuthenticationBuilder(new ClaimBuilder(claim).setClientId(clientId).build())
-                .setExpiration(tokenExpiration()).build();
-        tokenStore.put(token, auth);
-
-        final OAuthResponse r = OAuthASResponse.tokenResponse(SC_CREATED).setAccessToken(token)
-                .setTokenType(TokenType.BEARER.toString()).setExpiresIn(Long.toString(auth.expiration()))
-                .buildJSONMessage();
-        write(resp, r);
-    }
-
-    private void write(final HttpServletResponse resp, final OAuthResponse response) throws IOException {
-        resp.setStatus(response.getResponseStatus());
-        PrintWriter pw = resp.getWriter();
-        pw.print(response.getBody());
-        pw.flush();
-        pw.close();
-    }
-
-    private long tokenExpiration() {
-        return tokenStore.tokenExpiration();
-    }
-
-    /**
-     * Utility method used to emit an error OAuthResponse with the given HTTP code.
-     */
-    private void error(final HttpServletResponse resp, final int httpCode, final String error) {
-        try {
-            final OAuthResponse r = OAuthResponse.errorResponse(httpCode).setError(error).buildJSONMessage();
-            write(resp, r);
-        } catch (final IOException | OAuthSystemException ex) {
-            LOG.error("Failed to write the error ", ex);
-        }
-    }
-
-    private void error(final HttpServletResponse resp, final OAuthProblemException oauthProblemException) {
-        try {
-            final OAuthResponse r = OAuthResponse.errorResponse(SC_BAD_REQUEST).error(oauthProblemException)
-                    .buildJSONMessage();
-            write(resp, r);
-        } catch (final IOException | OAuthSystemException ex) {
-            LOG.error("Failed to write the error ", ex);
-        }
-    }
-
-    private void error(final HttpServletResponse resp, final Exception exception) {
-        try {
-            final OAuthResponse r = OAuthResponse.errorResponse(SC_INTERNAL_SERVER_ERROR)
-                    .setError(exception.getClass().getName()).setErrorDescription(exception.getMessage())
-                    .buildJSONMessage();
-            write(resp, r);
-        } catch (final IOException | OAuthSystemException ex) {
-            LOG.error("Failed to write the error ", ex);
-        }
-    }
-}
diff --git a/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/AnonymousPasswordValidator.java b/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/AnonymousPasswordValidator.java
deleted file mode 100644 (file)
index 1665c78..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2014 - 2017 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.shiro.oauth2;
-
-import javax.servlet.http.HttpServletRequest;
-import org.apache.oltu.oauth2.common.OAuth;
-import org.apache.oltu.oauth2.common.validators.AbstractValidator;
-
-/**
- * A password validator that does not enforce client identification.
- *
- * @author liemmn
- */
-public class AnonymousPasswordValidator extends AbstractValidator<HttpServletRequest> {
-
-    public AnonymousPasswordValidator() {
-        requiredParams.add(OAuth.OAUTH_GRANT_TYPE);
-        requiredParams.add(OAuth.OAUTH_USERNAME);
-        requiredParams.add(OAuth.OAUTH_PASSWORD);
-
-        enforceClientAuthentication = false;
-    }
-}
diff --git a/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/AnonymousRefreshTokenValidator.java b/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/AnonymousRefreshTokenValidator.java
deleted file mode 100644 (file)
index 8115c26..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2014 - 2017 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.shiro.oauth2;
-
-import javax.servlet.http.HttpServletRequest;
-import org.apache.oltu.oauth2.common.OAuth;
-import org.apache.oltu.oauth2.common.validators.AbstractValidator;
-
-/**
- * A refresh token validator that does not enforce client identification.
- *
- * @author liemmn
- */
-public class AnonymousRefreshTokenValidator extends AbstractValidator<HttpServletRequest> {
-
-    public AnonymousRefreshTokenValidator() {
-        requiredParams.add(OAuth.OAUTH_GRANT_TYPE);
-        requiredParams.add(OAuth.OAUTH_REFRESH_TOKEN);
-
-        enforceClientAuthentication = false;
-    }
-}
diff --git a/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/OAuth2TokenServlet.java b/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/OAuth2TokenServlet.java
deleted file mode 100644 (file)
index 48a5146..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (c) 2014, 2017 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.shiro.oauth2;
-
-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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-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.api.Authentication;
-import org.opendaylight.aaa.api.AuthenticationException;
-import org.opendaylight.aaa.api.AuthenticationService;
-import org.opendaylight.aaa.api.Claim;
-import org.opendaylight.aaa.api.CredentialAuth;
-import org.opendaylight.aaa.api.IdMService;
-import org.opendaylight.aaa.api.PasswordCredentials;
-import org.opendaylight.aaa.api.TokenStore;
-import org.opendaylight.aaa.shiro.tokenauthrealm.auth.AuthenticationBuilder;
-import org.opendaylight.aaa.shiro.tokenauthrealm.auth.ClaimBuilder;
-import org.opendaylight.aaa.shiro.tokenauthrealm.auth.PasswordCredentialBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Secure Token Service (STS) endpoint.
- *
- * @author liemmn
- */
-@SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED")
-public class OAuth2TokenServlet extends HttpServlet {
-    private static final Logger LOG = LoggerFactory.getLogger(OAuth2TokenServlet.class);
-    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 = "/oauth2/token";
-    static final String TOKEN_REVOKE_ENDPOINT = "/oauth2/revoke";
-    static final String TOKEN_VALIDATE_ENDPOINT = "/oauth2/validate";
-
-    private final transient CredentialAuth<PasswordCredentials> credentialAuth;
-    private final transient AuthenticationService authenticationService;
-    private final transient TokenStore tokenStore;
-    private final transient IdMService idmService;
-
-    private transient OAuthIssuer oi;
-
-    public OAuth2TokenServlet(CredentialAuth<PasswordCredentials> credentialAuth,
-            AuthenticationService authenticationService, TokenStore tokenStore, IdMService idmService) {
-        this.credentialAuth = credentialAuth;
-        this.authenticationService = authenticationService;
-        this.tokenStore = tokenStore;
-        this.idmService = idmService;
-    }
-
-    @Override
-    public void init(ServletConfig config) throws ServletException {
-        oi = new OAuthIssuerImpl(new UUIDValueGenerator());
-    }
-
-    @Override
-    public String getServletName() {
-        return OAuth2TokenServlet.class.getSimpleName();
-    }
-
-    @Override
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        final String requestURI = req.getRequestURI();
-        LOG.info("Token endpoint accessed: {} {}", req.getServletPath(), requestURI);
-        try {
-            if (requestURI.equals(TOKEN_GRANT_ENDPOINT)) {
-                createAccessToken(req, resp);
-            } else if (requestURI.equals(TOKEN_REVOKE_ENDPOINT)) {
-                deleteAccessToken(req, resp);
-            } else if (requestURI.equals(TOKEN_VALIDATE_ENDPOINT)) {
-                validateToken(req, resp);
-            }
-        } catch (final AuthenticationException e) {
-            error(resp, SC_UNAUTHORIZED, e.getMessage());
-        } catch (final OAuthProblemException oe) {
-            error(resp, oe);
-        } catch (final 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 = tokenStore.get(token.trim());
-            if (authn == null) {
-                throw new AuthenticationException(UNAUTHORIZED);
-            } else {
-                authenticationService.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 (tokenStore.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);
-
-        // 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 = credentialAuth.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 = tokenStore.get(token);
-                if (auth != null && domain != null) {
-                    List<String> roles = idmService.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();
-        tokenStore.put(token, auth);
-
-        OAuthResponse response = OAuthASResponse.tokenResponse(SC_CREATED).setAccessToken(token)
-                                         .setTokenType(TokenType.BEARER.toString())
-                                         .setExpiresIn(Long.toString(auth.expiration()))
-                                         .buildJSONMessage();
-        write(resp, response);
-    }
-
-    // Token expiration
-    private long tokenExpiration() {
-        return tokenStore.tokenExpiration();
-    }
-
-    // Emit an error OAuthResponse with the given HTTP code
-    private void error(HttpServletResponse resp, int httpCode, String error) {
-        try {
-            OAuthResponse response = OAuthResponse.errorResponse(httpCode).setError(error)
-                                           .buildJSONMessage();
-            write(resp, response);
-        } catch (IOException | OAuthSystemException e) {
-            // Nothing to do here
-        }
-    }
-
-    // Emit an error OAuthResponse for the given OAuth-related exception
-    private void error(HttpServletResponse resp, OAuthProblemException exception) {
-        try {
-            OAuthResponse response = OAuthResponse.errorResponse(SC_BAD_REQUEST).error(exception)
-                                           .buildJSONMessage();
-            write(resp, response);
-        } catch (IOException | OAuthSystemException e) {
-            // Nothing to do here
-        }
-    }
-
-    // Emit an error OAuthResponse for the given generic exception
-    private void error(HttpServletResponse resp, Exception exception) {
-        try {
-            OAuthResponse response = OAuthResponse.errorResponse(SC_INTERNAL_SERVER_ERROR)
-                                           .setError(exception.getClass().getName())
-                                           .setErrorDescription(exception.getMessage()).buildJSONMessage();
-            write(resp, response);
-        } catch (IOException | OAuthSystemException e) {
-            // Nothing to do here
-        }
-    }
-
-    // Write out an OAuthResponse
-    private void write(HttpServletResponse resp, OAuthResponse response) throws IOException {
-        resp.setStatus(response.getResponseStatus());
-        PrintWriter pw = resp.getWriter();
-        pw.print(response.getBody());
-        pw.flush();
-        pw.close();
-    }
-}
diff --git a/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/OAuthRequest.java b/aaa-shiro/impl/src/main/java/org/opendaylight/aaa/shiro/oauth2/OAuthRequest.java
deleted file mode 100644 (file)
index 3b91139..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2014 - 2017 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.shiro.oauth2;
-
-import javax.servlet.http.HttpServletRequest;
-import org.apache.oltu.oauth2.as.request.AbstractOAuthTokenRequest;
-import org.apache.oltu.oauth2.as.validator.UnauthenticatedAuthorizationCodeValidator;
-import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
-import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
-import org.apache.oltu.oauth2.common.message.types.GrantType;
-import org.apache.oltu.oauth2.common.validators.OAuthValidator;
-
-/**
- * OAuth request wrapper.
- *
- * @author liemmn
- */
-public class OAuthRequest extends AbstractOAuthTokenRequest {
-
-    public OAuthRequest(HttpServletRequest request) throws OAuthSystemException,
-            OAuthProblemException {
-        super(request);
-    }
-
-    @Override
-    public OAuthValidator<HttpServletRequest> initValidator() throws OAuthProblemException,
-            OAuthSystemException {
-        validators.put(GrantType.PASSWORD.toString(), AnonymousPasswordValidator.class);
-        validators.put(GrantType.REFRESH_TOKEN.toString(), AnonymousRefreshTokenValidator.class);
-        validators.put(GrantType.AUTHORIZATION_CODE.toString(),
-                UnauthenticatedAuthorizationCodeValidator.class);
-        return super.initValidator();
-    }
-
-}
diff --git a/aaa-shiro/impl/src/test/java/org/opendaylight/aaa/shiro/oauth2/OAuth2TokenServletTest.java b/aaa-shiro/impl/src/test/java/org/opendaylight/aaa/shiro/oauth2/OAuth2TokenServletTest.java
deleted file mode 100644 (file)
index ca75c94..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2014, 2017 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.shiro.oauth2;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mortbay.jetty.testing.HttpTester;
-import org.mortbay.jetty.testing.ServletTester;
-import org.opendaylight.aaa.api.Claim;
-import org.opendaylight.aaa.api.CredentialAuth;
-import org.opendaylight.aaa.api.IdMService;
-import org.opendaylight.aaa.api.PasswordCredentials;
-import org.opendaylight.aaa.api.TokenStore;
-import org.opendaylight.aaa.shiro.tokenauthrealm.auth.AuthenticationBuilder;
-import org.opendaylight.aaa.shiro.tokenauthrealm.auth.ClaimBuilder;
-
-/**
- * A unit test for token endpoint.
- *
- * @author liemmn
- *
- */
-@Ignore
-public class OAuth2TokenServletTest {
-    private static final long TOKEN_TIMEOUT_SECS = 10;
-    private static final String CONTEXT = "/oauth2";
-    private static final String DIRECT_AUTH =
-            "grant_type=password&username=admin&password=admin&scope=pepsi&client_id=dlux&client_secret=secrete";
-    private static final String REFRESH_TOKEN = "grant_type=refresh_token&refresh_token=whateverisgood&scope=pepsi";
-
-    private static final Claim CLAIM = new ClaimBuilder().setUser("bob").setUserId("1234")
-
-                                                         .addRole("admin").build();
-    private static final ServletTester SERVER = new ServletTester();
-
-    @Mock
-    private CredentialAuth<PasswordCredentials> mockCredentialAuth;
-
-    @Mock
-    private IdMService mockIdMService;
-
-    @Mock
-    private TokenStore mockTokenStore;
-
-    @BeforeClass
-    public static void init() throws Exception {
-        // Set up SERVER
-        SERVER.setContextPath(CONTEXT);
-
-        // Add our servlet under test
-        SERVER.addServlet(OAuth2TokenServlet.class, "/revoke");
-        SERVER.addServlet(OAuth2TokenServlet.class, "/token");
-
-        // Let's do dis
-        SERVER.start();
-    }
-
-    @AfterClass
-    public static void shutdown() throws Exception {
-        SERVER.stop();
-    }
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        when(mockTokenStore.tokenExpiration()).thenReturn(TOKEN_TIMEOUT_SECS);
-    }
-
-    @Test
-    public void testCreateToken401() throws Exception {
-        HttpTester req = new HttpTester();
-        req.setMethod("POST");
-        req.setHeader("Content-Type", "application/x-www-form-urlencoded");
-        req.setContent(DIRECT_AUTH);
-        req.setURI(CONTEXT + OAuth2TokenServlet.TOKEN_GRANT_ENDPOINT);
-        req.setVersion("HTTP/1.0");
-
-        HttpTester resp = new HttpTester();
-        resp.parse(SERVER.getResponses(req.generate()));
-        Assert.assertEquals(401, resp.getStatus());
-    }
-
-    @Test
-    public void testCreateTokenWithPassword() throws Exception {
-        when(mockCredentialAuth.authenticate(any(PasswordCredentials.class))).thenReturn(CLAIM);
-
-        HttpTester req = new HttpTester();
-        req.setMethod("POST");
-        req.setHeader("Content-Type", "application/x-www-form-urlencoded");
-        req.setContent(DIRECT_AUTH);
-        req.setURI(CONTEXT + OAuth2TokenServlet.TOKEN_GRANT_ENDPOINT);
-        req.setVersion("HTTP/1.0");
-
-        HttpTester resp = new HttpTester();
-        resp.parse(SERVER.getResponses(req.generate()));
-        Assert.assertEquals(201, resp.getStatus());
-        assertTrue(resp.getContent().contains("expires_in\":10"));
-        assertTrue(resp.getContent().contains("Bearer"));
-    }
-
-    @Test
-    public void testCreateTokenWithRefreshToken() throws Exception {
-        when(mockTokenStore.get(anyString())).thenReturn(new AuthenticationBuilder(CLAIM).build());
-        when(mockIdMService.listRoles(anyString(), anyString())).thenReturn(Arrays.asList("admin", "user"));
-
-        HttpTester req = new HttpTester();
-        req.setMethod("POST");
-        req.setHeader("Content-Type", "application/x-www-form-urlencoded");
-        req.setContent(REFRESH_TOKEN);
-        req.setURI(CONTEXT + OAuth2TokenServlet.TOKEN_GRANT_ENDPOINT);
-        req.setVersion("HTTP/1.0");
-
-        HttpTester resp = new HttpTester();
-        resp.parse(SERVER.getResponses(req.generate()));
-        Assert.assertEquals(201, resp.getStatus());
-        assertTrue(resp.getContent().contains("expires_in\":10"));
-        assertTrue(resp.getContent().contains("Bearer"));
-    }
-
-    @Test
-    public void testDeleteToken() throws Exception {
-        when(mockTokenStore.delete("token_to_be_deleted")).thenReturn(true);
-
-        HttpTester req = new HttpTester();
-        req.setMethod("POST");
-        req.setHeader("Content-Type", "application/x-www-form-urlencoded");
-        req.setContent("token_to_be_deleted");
-        req.setURI(CONTEXT + OAuth2TokenServlet.TOKEN_REVOKE_ENDPOINT);
-        req.setVersion("HTTP/1.0");
-
-        HttpTester resp = new HttpTester();
-        resp.parse(SERVER.getResponses(req.generate()));
-        Assert.assertEquals(204, resp.getStatus());
-    }
-}
index 30641dae1acb59ecfa5d88e563ddbd03bb04336d..e7d8deb599de24b4fbd54d70b5829feee6306c04 100644 (file)
             <type>xml</type>
             <classifier>features</classifier>
         </dependency>
-        <dependency>
-            <groupId>org.json</groupId>
-            <artifactId>json</artifactId>
-        </dependency>
         <dependency>
             <groupId>org.apache.shiro</groupId>
             <artifactId>shiro-web</artifactId>
             <artifactId>shiro-core</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.apache.oltu.oauth2</groupId>
-            <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.oltu.oauth2</groupId>
-            <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.oltu.oauth2</groupId>
-            <artifactId>org.apache.oltu.oauth2.common</artifactId>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.aaa</groupId>
index dc2158861a5dfe9797a5b3fa99aa3d6e9a292bb7..a9d17aa2ca89147a006e725e07fed8eba94102d1 100644 (file)
   <name>ODL :: aaa :: ${project.artifactId}</name>
   <packaging>pom</packaging>
 
-  <properties>
-    <!-- AuthN -->
-    <oltu.version>1.0.2</oltu.version>
-  </properties>
 
   <dependencyManagement>
     <dependencies>
       </dependency>
 
       <!-- Third-party -->
-      <dependency>
-        <groupId>org.glassfish</groupId>
-        <artifactId>javax.json</artifactId>
-        <version>1.0.4</version>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>org.apache.felix.metatype</artifactId>
-      </dependency>
       <dependency>
         <groupId>net.sf.ehcache</groupId>
         <artifactId>ehcache</artifactId>
         <version>2.10.6</version>
       </dependency>
       <dependency>
-        <groupId>org.apache.oltu.oauth2</groupId>
-        <artifactId>org.apache.oltu.oauth2.common</artifactId>
-        <version>${oltu.version}</version>
-        <exclusions>
-          <exclusion>
-            <!-- This is clashing with jackson's view of org.json world -->
-            <groupId>org.json</groupId>
-            <artifactId>json</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.oltu.oauth2</groupId>
-        <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
-        <version>${oltu.version}</version>
-        <exclusions>
-          <exclusion>
-            <!-- This is clashing with jackson's view of org.json world -->
-            <groupId>org.json</groupId>
-            <artifactId>json</artifactId>
-          </exclusion>
-        </exclusions>
+        <groupId>org.glassfish</groupId>
+        <artifactId>javax.json</artifactId>
+        <version>1.0.4</version>
       </dependency>
       <dependency>
-        <groupId>org.apache.oltu.oauth2</groupId>
-        <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
-        <version>${oltu.version}</version>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.metatype</artifactId>
       </dependency>
 
       <!-- Test stuff -->