/* * Copyright 2012 SURFnet bv, The Netherlands * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.surfnet.oaaas.auth; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.surfnet.oaaas.auth.OAuth2Validator.ValidationResponse; import org.surfnet.oaaas.model.AuthorizationRequest; import org.surfnet.oaaas.repository.AuthorizationRequestRepository; import javax.inject.Inject; import javax.inject.Named; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.util.Arrays; import java.util.List; import java.util.UUID; @Named public class AuthenticationFilter implements Filter { private static final Logger LOG = LoggerFactory.getLogger(AuthenticationFilter.class); private AbstractAuthenticator authenticator; @Inject private AuthorizationRequestRepository authorizationRequestRepository; @Inject private OAuth2Validator oAuth2Validator; @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; /* * Create an authorizationRequest from the request parameters. * This can be either a valid or an invalid request, which will be determined by the oAuth2Validator. */ AuthorizationRequest authorizationRequest = extractAuthorizationRequest(request); final ValidationResponse validationResponse = oAuth2Validator.validate(authorizationRequest); if (authenticator.canCommence(request)) { /* * Ok, the authenticator wants to have control again (because he stepped * out) */ authenticator.doFilter(request, response, chain); } else if (validationResponse.valid()) { // Request contains correct parameters to be a real OAuth2 request. handleInitialRequest(authorizationRequest, request); authenticator.doFilter(request, response, chain); } else { // not an initial request but authentication module cannot handle it either sendError(response, authorizationRequest, validationResponse); } } protected AuthorizationRequest extractAuthorizationRequest(HttpServletRequest request) { String responseType = request.getParameter("response_type"); String clientId = request.getParameter("client_id"); String redirectUri = request.getParameter("redirect_uri"); List<String> requestedScopes = null; if (StringUtils.isNotBlank(request.getParameter("scope"))) { requestedScopes = Arrays.asList(request.getParameter("scope").split(",")); } String state = request.getParameter("state"); String authState = getAuthStateValue(); return new AuthorizationRequest(responseType, clientId, redirectUri, requestedScopes, state, authState); } private boolean handleInitialRequest(AuthorizationRequest authReq, HttpServletRequest request) throws ServletException { try { authorizationRequestRepository.save(authReq); } catch (Exception e) { LOG.error("while saving authorization request", e); throw new ServletException("Cannot save authorization request"); } request.setAttribute(AbstractAuthenticator.AUTH_STATE, authReq.getAuthState()); request.setAttribute(AbstractAuthenticator.RETURN_URI, request.getRequestURI()); return true; } protected String getAuthStateValue() { return UUID.randomUUID().toString(); } private void sendError(HttpServletResponse response, AuthorizationRequest authReq, ValidationResponse validate) throws IOException { LOG.info("Will send error response for authorization request '{}', validation result: {}", authReq, validate); String redirectUri = authReq.getRedirectUri(); String state = authReq.getState(); if (isValidUri(redirectUri)) { redirectUri = redirectUri.concat(redirectUri.contains("?") ? "&" : "?"); redirectUri = redirectUri .concat("error=").concat(validate.getValue()) .concat("&error_description=").concat(validate.getDescription()) .concat(StringUtils.isBlank(state) ? "" : "&state=".concat(URLEncoder.encode(state, "UTF-8"))); LOG.info("Sending error response, a redirect to: {}", redirectUri); response.sendRedirect(redirectUri); } else { LOG.info("Sending error response 'bad request': {}", validate.getDescription()); response.sendError(HttpServletResponse.SC_BAD_REQUEST, validate.getDescription()); } } @Override public void destroy() { } @Override public void init(FilterConfig filterConfig) throws ServletException { } public void setAuthenticator(AbstractAuthenticator authenticator) { this.authenticator = authenticator; } public static boolean isValidUri(String redirectUri) { try { URI uri = new URI(redirectUri); if (uri.getScheme() != null) { return true; } else { return false; } } catch (URISyntaxException e) { return false; } } /** * @param authorizationRequestRepository * the authorizationRequestRepository to set */ public void setAuthorizationRequestRepository(AuthorizationRequestRepository authorizationRequestRepository) { this.authorizationRequestRepository = authorizationRequestRepository; } /** * @param oAuth2Validator * the oAuth2Validator to set */ public void setOAuth2Validator(OAuth2Validator oAuth2Validator) { this.oAuth2Validator = oAuth2Validator; } }