From e63b03f3d7e4851e008e4bb4d184982c2c0bd229 Mon Sep 17 00:00:00 2001 From: WuKong Date: Tue, 24 May 2016 17:13:17 +0200 Subject: odl/aaa clone Change-Id: I2b72c16aa3245e02d985a2c6189aacee7caad36e Signed-off-by: WuKong --- .../org/opendaylight/aaa/sts/TokenAuthFilter.java | 148 +++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 odl-aaa-moon/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenAuthFilter.java (limited to 'odl-aaa-moon/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenAuthFilter.java') diff --git a/odl-aaa-moon/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenAuthFilter.java b/odl-aaa-moon/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenAuthFilter.java new file mode 100644 index 00000000..3fa7a66c --- /dev/null +++ b/odl-aaa-moon/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenAuthFilter.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.sts; + +import com.sun.jersey.spi.container.ContainerRequest; +import com.sun.jersey.spi.container.ContainerRequestFilter; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import org.apache.oltu.oauth2.common.exception.OAuthProblemException; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.apache.oltu.oauth2.common.message.types.ParameterStyle; +import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest; +import org.opendaylight.aaa.api.Authentication; +import org.opendaylight.aaa.api.AuthenticationException; +import org.opendaylight.aaa.api.TokenAuth; + +/** + * A token-based authentication filter for resource providers. + * + * Deprecated: Use AAAFilter instead. + * + * @author liemmn + * + */ +@Deprecated +public class TokenAuthFilter implements ContainerRequestFilter { + + private final String OPTIONS = "OPTIONS"; + private final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers"; + private final String AUTHORIZATION = "authorization"; + + @Context + private HttpServletRequest httpRequest; + + @Override + public ContainerRequest filter(ContainerRequest request) { + + // Do the CORS check first + if (checkCORSOptionRequest(request)) { + return request; + } + + // Are we up yet? + if (ServiceLocator.getInstance().getAuthenticationService() == null) { + throw new WebApplicationException( + Response.status(Status.SERVICE_UNAVAILABLE).type(MediaType.APPLICATION_JSON) + .entity("{\"error\":\"Authentication service unavailable\"}").build()); + } + + // Are we doing authentication or not? + if (ServiceLocator.getInstance().getAuthenticationService().isAuthEnabled()) { + Map> headers = request.getRequestHeaders(); + + // Go through and invoke other TokenAuth first... + List tokenAuthCollection = ServiceLocator.getInstance() + .getTokenAuthCollection(); + for (TokenAuth ta : tokenAuthCollection) { + try { + Authentication auth = ta.validate(headers); + if (auth != null) { + ServiceLocator.getInstance().getAuthenticationService().set(auth); + return request; + } + } catch (AuthenticationException ae) { + throw unauthorized(); + } + } + + // OK, last chance to validate token... + try { + OAuthAccessResourceRequest or = new OAuthAccessResourceRequest(httpRequest, + ParameterStyle.HEADER); + validate(or.getAccessToken()); + } catch (OAuthSystemException | OAuthProblemException e) { + throw unauthorized(); + } + } + + return request; + } + + /** + * CORS access control : when browser sends cross-origin request, it first + * sends the OPTIONS method with a list of access control request headers, + * which has a list of custom headers and access control method such as GET. + * POST etc. You custom header "Authorization will not be present in request + * header, instead it will be present as a value inside + * Access-Control-Request-Headers. We should not do any authorization + * against such request. for more details : + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS + */ + + private boolean checkCORSOptionRequest(ContainerRequest request) { + if (OPTIONS.equals(request.getMethod())) { + List headerList = request.getRequestHeader(ACCESS_CONTROL_REQUEST_HEADERS); + if (headerList != null && !headerList.isEmpty()) { + String header = headerList.get(0); + if (header != null && header.toLowerCase().contains(AUTHORIZATION)) { + return true; + } + } + } + return false; + } + + // Validate an ODL token... + private Authentication validate(final String token) { + Authentication auth = ServiceLocator.getInstance().getTokenStore().get(token); + if (auth == null) { + throw unauthorized(); + } else { + ServiceLocator.getInstance().getAuthenticationService().set(auth); + } + return auth; + } + + // Houston, we got a problem! + private static final WebApplicationException unauthorized() { + ServiceLocator.getInstance().getAuthenticationService().clear(); + return new UnauthorizedException(); + } + + // A custom 401 web exception that handles http basic response as well + static final class UnauthorizedException extends WebApplicationException { + private static final long serialVersionUID = -1732363804773027793L; + static final String WWW_AUTHENTICATE = "WWW-Authenticate"; + static final Object OPENDAYLIGHT = "Basic realm=\"opendaylight\""; + private static final Response response = Response.status(Status.UNAUTHORIZED) + .header(WWW_AUTHENTICATE, OPENDAYLIGHT) + .build(); + + public UnauthorizedException() { + super(response); + } + } +} -- cgit 1.2.3-korg