diff options
Diffstat (limited to 'upstream/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters')
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); + } + } +} |