aboutsummaryrefslogtreecommitdiffstats
path: root/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters
diff options
context:
space:
mode:
Diffstat (limited to 'upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters')
-rw-r--r--upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAFilter.java72
-rw-r--r--upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAShiroFilter.java51
-rw-r--r--upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationListener.java52
-rw-r--r--upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtils.java129
-rw-r--r--upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java186
-rw-r--r--upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/ODLHttpAuthenticationFilter.java78
6 files changed, 568 insertions, 0 deletions
diff --git a/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAFilter.java b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAFilter.java
new file mode 100644
index 00000000..47dd9549
--- /dev/null
+++ b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAFilter.java
@@ -0,0 +1,72 @@
+/*
+ * 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.filters;
+
+import org.apache.shiro.web.servlet.ShiroFilter;
+import org.opendaylight.aaa.shiro.ServiceProxy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The RESTCONF AAA JAX-RS 1.X Web Filter. This class is also responsible for
+ * delivering debug information; to enable these debug statements, please issue
+ * the following in the karaf shell:
+ *
+ * <code>log:set debug org.opendaylight.aaa.shiro.filters.AAAFilter</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ * @see <code>javax.servlet.Filter</code>
+ * @see <code>org.apache.shiro.web.servlet.ShiroFilter</code>
+ */
+public class AAAFilter extends ShiroFilter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AAAFilter.class);
+
+ public AAAFilter() {
+ super();
+ final String DEBUG_MESSAGE = "Creating the AAAFilter";
+ LOG.debug(DEBUG_MESSAGE);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * Adds context clues that aid in debugging. Also initializes the enable
+ * status to correspond with
+ * <code>ServiceProxy.getInstance.getEnabled()</code>.
+ *
+ * @see org.apache.shiro.web.servlet.ShiroFilter#init()
+ */
+ @Override
+ public void init() throws Exception {
+ super.init();
+ final String DEBUG_MESSAGE = "Initializing the AAAFilter";
+ LOG.debug(DEBUG_MESSAGE);
+ // sets the filter to the startup value. Because of non-determinism in
+ // bundle loading, this passes an instance of itself along so that if
+ // the
+ // enable status changes, then AAAFilter enable status is changed.
+ setEnabled(ServiceProxy.getInstance().getEnabled(this));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * Adds context clues to aid in debugging whether the filter is enabled.
+ *
+ * @see
+ * org.apache.shiro.web.servlet.OncePerRequestFilter#setEnabled(boolean)
+ */
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ final String DEBUG_MESSAGE = "Setting AAAFilter enabled to " + enabled;
+ LOG.debug(DEBUG_MESSAGE);
+ }
+}
diff --git a/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAShiroFilter.java b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAShiroFilter.java
new file mode 100644
index 00000000..530acfac
--- /dev/null
+++ b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAShiroFilter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 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.filters;
+
+import org.apache.shiro.web.servlet.ShiroFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The default AAA JAX-RS 1.X Web Filter. Unlike AAAFilter, which is aimed towards
+ * supporting RESTCONF and its existing API mechanisms, AAAShiroFilter is a generic
+ * <code>ShiroFilter</code> for use with any other ODL Servlets. The main difference
+ * is that <code>AAAFilter</code> was designed to support the existing noauth
+ * mechanism, while this filter cannot be disabled.
+ *
+ * This class is also responsible for delivering debug information; to enable these
+ * debug statements, please issue the following in the karaf shell:
+ *
+ * <code>log:set debug org.opendaylight.aaa.shiro.filters.AAAShiroFilter</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ * @see <code>javax.servlet.Filter</code>
+ * @see <code>org.apache.shiro.web.servlet.ShiroFilter</code>
+ */
+public class AAAShiroFilter extends ShiroFilter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AAAShiroFilter.class);
+
+ public AAAShiroFilter() {
+ LOG.debug("Creating the AAAShiroFilter");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * Adds context clues that aid in debugging.
+ *
+ * @see org.apache.shiro.web.servlet.ShiroFilter#init()
+ */
+ @Override
+ public void init() throws Exception {
+ super.init();
+ LOG.debug("Initializing the AAAShiroFilter");
+ }
+}
diff --git a/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationListener.java b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationListener.java
new file mode 100644
index 00000000..080ab114
--- /dev/null
+++ b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationListener.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 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.filters;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Follows the event-listener pattern; the <code>Authenticator</code> notifies this class about
+ * authentication attempts. <code>AuthenticationListener</code> logs successful and unsuccessful
+ * authentication attempts appropriately. Log messages are emitted at the <code>DEBUG</code> log
+ * level. To enable the messages out of the box, use the following command from karaf:
+ * <code>log:set DEBUG org.opendaylight.aaa.shiro.authc.AuthenicationListener</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class AuthenticationListener implements org.apache.shiro.authc.AuthenticationListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AuthenticationListener.class);
+
+ @Override
+ public void onSuccess(final AuthenticationToken authenticationToken, final AuthenticationInfo authenticationInfo) {
+ if (LOG.isDebugEnabled()) {
+ final String successMessage = AuthenticationTokenUtils.generateSuccessfulAuthenticationMessage(authenticationToken);
+ LOG.debug(successMessage);
+ }
+ }
+
+ @Override
+ public void onFailure(final AuthenticationToken authenticationToken, final AuthenticationException e) {
+ if (LOG.isDebugEnabled()) {
+ final String failureMessage = AuthenticationTokenUtils.generateUnsuccessfulAuthenticationMessage(authenticationToken);
+ LOG.debug(failureMessage);
+ }
+ }
+
+ @Override
+ public void onLogout(final PrincipalCollection principalCollection) {
+ // Do nothing; AAA is aimed at RESTCONF, which stateless by definition.
+ // Including this output would very quickly pollute the log.
+ }
+}
diff --git a/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtils.java b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtils.java
new file mode 100644
index 00000000..a5f0c10d
--- /dev/null
+++ b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtils.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016 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.filters;
+
+import com.google.common.base.Preconditions;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+
+/**
+ * Utility methods for forming audit trail output based on an <code>AuthenticationToken</code>.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class AuthenticationTokenUtils {
+
+ /**
+ * default value used in messaging when the "user" field is unparsable from the HTTP REST request
+ */
+ static final String DEFAULT_USERNAME = "an unknown user";
+
+ /**
+ * default value used in messaging when the "user" field is not present in the HTTP REST request, implying
+ * a different implementation of <code>AuthenticationToken</code> such as <code>CasToken</code>.
+ */
+ static final String DEFAULT_TOKEN = "an un-parsable token type";
+
+ /**
+ * default value used in messaging when the "host" field cannot be determined.
+ */
+ static final String DEFAULT_HOSTNAME = "an unknown host";
+
+ private AuthenticationTokenUtils() {
+ // private to prevent instantiation
+ }
+
+ /**
+ * Determines whether the supplied <code>Token</code> is a <code>UsernamePasswordToken</code>.
+ *
+ * @param token A generic <code>Token</code>, which might be a <code>UsernamePasswordToken</code>
+ * @return Whether the supplied <code>Token</code> is a <code>UsernamePasswordToken</code>
+ */
+ public static boolean isUsernamePasswordToken(final AuthenticationToken token) {
+ return token instanceof UsernamePasswordToken;
+ }
+
+ /**
+ * Extracts the username if possible. If the supplied token is a <code>UsernamePasswordToken</code>
+ * and the username field is not set, <code>DEFAULT_USERNAME</code> is returned. If the supplied
+ * token is not a <code>UsernamePasswordToken</code> (i.e., a <code>CasToken</code> or other
+ * implementation of <code>AuthenticationToken</code>), then <code>DEFAULT_TOKEN</code> is
+ * returned.
+ *
+ * @param token An <code>AuthenticationToken</code>, possibly a <code>UsernamePasswordToken</code>
+ * @return the username, <code>DEFAULT_USERNAME</code> or <code>DEFAULT_TOKEN</code> depending on input
+ */
+ public static String extractUsername(final AuthenticationToken token) {
+ if (isUsernamePasswordToken(token)) {
+ final UsernamePasswordToken upt = (UsernamePasswordToken) token;
+ return extractField(upt.getUsername(), DEFAULT_USERNAME);
+ }
+ return DEFAULT_TOKEN;
+ }
+
+ /**
+ * Extracts the hostname if possible. If the supplied token is a <code>UsernamePasswordToken</code>
+ * and the hostname field is not set, <code>DEFAULT_HOSTNAME</code> is returned. If the supplied
+ * token is not a <code>UsernamePasswordToken</code> (i.e., a <code>CasToken</code> or other
+ * implementation of <code>AuthenticationToken</code>), then <code>DEFAULT_HOSTNAME</code> is
+ * returned.
+ *
+ * @param token An <code>AuthenticationToken</code>, possibly a <code>UsernamePasswordToken</code>
+ * @return the hostname, or <code>DEFAULT_USERNAME</code> depending on input
+ */
+ public static String extractHostname(final AuthenticationToken token) {
+ if (isUsernamePasswordToken(token)) {
+ final UsernamePasswordToken upt = (UsernamePasswordToken) token;
+ return extractField(upt.getHost(), DEFAULT_HOSTNAME);
+ }
+ return DEFAULT_HOSTNAME;
+ }
+
+ /**
+ * Utility method to generate a generic message indicating Authentication was unsuccessful.
+ *
+ * @param token An <code>AuthenticationToken</code>, possibly a <code>UsernamePasswordToken</code>
+ * @return A message indicating authentication was unsuccessful
+ */
+ public static String generateUnsuccessfulAuthenticationMessage(final AuthenticationToken token) {
+ final String username = extractUsername(token);
+ final String remoteHostname = extractHostname(token);
+ return String.format("Unsuccessful authentication attempt by %s from %s", username, remoteHostname);
+ }
+
+ /**
+ * Utility method to generate a generic message indicating Authentication was successful.
+ *
+ * @param token An <code>AuthenticationToken</code>, possibly a <code>UsernamePasswordToken</code>
+ * @return A message indicating authentication was successful
+ */
+ public static String generateSuccessfulAuthenticationMessage(final AuthenticationToken token) {
+ final String username = extractUsername(token);
+ final String remoteHostname = extractHostname(token);
+ return String.format("Successful authentication attempt by %s from %s", username, remoteHostname);
+ }
+
+ /**
+ * Utility method that returns <code>field</code>, or <code>defaultValue</code> if <code>field</code> is null.
+ *
+ * @param field A generic string, which is possibly null.
+ * @param defaultValue A non-null value returned if <code>field</code> is null
+ * @return <code>field</code> or <code>defaultValue</code> if field is null
+ * @throws IllegalArgumentException If <code>defaultValue</code> is null
+ */
+ private static String extractField(final String field, final String defaultValue)
+ throws IllegalArgumentException {
+
+ Preconditions.checkNotNull(defaultValue, "defaultValue can't be null");
+ if (field != null) {
+ return field;
+ }
+ return defaultValue;
+ }
+}
diff --git a/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java
new file mode 100644
index 00000000..241b7c28
--- /dev/null
+++ b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java
@@ -0,0 +1,186 @@
+/*
+ * 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.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.AuthenticationBuilder;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.shiro.moon.MoonPrincipal;
+import org.opendaylight.aaa.sts.OAuthRequest;
+import org.opendaylight.aaa.sts.ServiceLocator;
+
+/**
+ * MoonOAuthFilter filters oauth1 requests form token based authentication
+ * @author Alioune BA alioune.ba@orange.com
+ *
+ */
+public class MoonOAuthFilter extends AuthenticatingFilter{
+
+ private static final String DOMAIN_SCOPE_REQUIRED = "Domain scope required";
+ private static final String NOT_IMPLEMENTED = "not_implemented";
+ 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";
+
+ @Override
+ protected UsernamePasswordToken createToken(ServletRequest request, ServletResponse response) throws Exception {
+ // TODO Auto-generated method stub
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ OAuthRequest oauthRequest = new OAuthRequest(httpRequest);
+ return new UsernamePasswordToken(oauthRequest.getUsername(),oauthRequest.getPassword());
+ }
+
+ @Override
+ protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+ // TODO Auto-generated method stub
+ Subject currentUser = SecurityUtils.getSubject();
+ return executeLogin(request, response);
+ }
+
+ protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
+ ServletRequest request, ServletResponse response) throws Exception {
+ HttpServletResponse httpResponse= (HttpServletResponse) response;
+ MoonPrincipal principal = (MoonPrincipal) subject.getPrincipals().getPrimaryPrincipal();
+ Claim claim = principal.principalToClaim();
+ oauthAccessTokenResponse(httpResponse,claim,"",principal.getToken());
+ return true;
+ }
+
+ protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e,
+ ServletRequest request, ServletResponse response) {
+ HttpServletResponse resp = (HttpServletResponse) response;
+ error(resp, SC_BAD_REQUEST, UNAUTHORIZED_CREDENTIALS);
+ return false;
+ }
+
+ protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
+
+ HttpServletRequest req= (HttpServletRequest) request;
+ HttpServletResponse resp = (HttpServletResponse) response;
+ try {
+ if (req.getServletPath().equals(TOKEN_GRANT_ENDPOINT)) {
+ UsernamePasswordToken token = createToken(request, response);
+ if (token == null) {
+ String msg = "A valid non-null AuthenticationToken " +
+ "must be created in order to execute a login attempt.";
+ throw new IllegalStateException(msg);
+ }
+ try {
+ Subject subject = getSubject(request, response);
+ subject.login(token);
+ return onLoginSuccess(token, subject, request, response);
+ } catch (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 (AuthenticationException e) {
+ error(resp, SC_UNAUTHORIZED, e.getMessage());
+ } catch (OAuthProblemException oe) {
+ error(resp, oe);
+ } catch (Exception e) {
+ error(resp, e);
+ }
+ return false;
+ }
+
+ private void oauthAccessTokenResponse(HttpServletResponse resp, Claim claim, String clientId, String token)
+ throws OAuthSystemException, IOException {
+ if (claim == null) {
+ throw new AuthenticationException(UNAUTHORIZED);
+ }
+
+ // 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);
+ }
+
+ 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();
+ }
+
+ 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
+ }
+ }
+
+ 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
+ }
+ }
+
+ 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
+ }
+ }
+
+}
diff --git a/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/ODLHttpAuthenticationFilter.java b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/ODLHttpAuthenticationFilter.java
new file mode 100644
index 00000000..90b0101e
--- /dev/null
+++ b/upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/ODLHttpAuthenticationFilter.java
@@ -0,0 +1,78 @@
+/*
+ * 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.filters;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.shiro.codec.Base64;
+import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
+import org.apache.shiro.web.util.WebUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Extends <code>BasicHttpAuthenticationFilter</code> to include ability to
+ * authenticate OAuth2 tokens, which is needed for backwards compatibility with
+ * <code>TokenAuthFilter</code>.
+ *
+ * This behavior is enabled by default for backwards compatibility. To disable
+ * OAuth2 functionality, just comment out the following line from the
+ * <code>etc/shiro.ini</code> file:
+ * <code>authcBasic = org.opendaylight.aaa.shiro.filters.ODLHttpAuthenticationFilter</code>
+ * then restart the karaf container.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ *
+ */
+public class ODLHttpAuthenticationFilter extends BasicHttpAuthenticationFilter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ODLHttpAuthenticationFilter.class);
+
+ // defined in lower-case for more efficient string comparison
+ protected static final String BEARER_SCHEME = "bearer";
+
+ protected static final String OPTIONS_HEADER = "OPTIONS";
+
+ public ODLHttpAuthenticationFilter() {
+ super();
+ LOG.info("Creating the ODLHttpAuthenticationFilter");
+ }
+
+ @Override
+ protected String[] getPrincipalsAndCredentials(String scheme, String encoded) {
+ final String decoded = Base64.decodeToString(encoded);
+ // attempt to decode username/password; otherwise decode as token
+ if (decoded.contains(":")) {
+ return decoded.split(":");
+ }
+ return new String[] { encoded };
+ }
+
+ @Override
+ protected boolean isLoginAttempt(String authzHeader) {
+ final String authzScheme = getAuthzScheme().toLowerCase();
+ final String authzHeaderLowerCase = authzHeader.toLowerCase();
+ return authzHeaderLowerCase.startsWith(authzScheme)
+ || authzHeaderLowerCase.startsWith(BEARER_SCHEME);
+ }
+
+ @Override
+ protected boolean isAccessAllowed(ServletRequest request, ServletResponse response,
+ Object mappedValue) {
+ final HttpServletRequest httpRequest = WebUtils.toHttp(request);
+ final String httpMethod = httpRequest.getMethod();
+ if (OPTIONS_HEADER.equalsIgnoreCase(httpMethod)) {
+ return true;
+ } else {
+ return super.isAccessAllowed(httpRequest, response, mappedValue);
+ }
+ }
+}