/* * ****************************************************************************** * Cloud Foundry * Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved. * * This product is licensed to you under the Apache License, Version 2.0 (the "License"). * You may not use this product except in compliance with the License. * * This product includes a number of subcomponents with * separate copyright notices and license terms. Your use of these * subcomponents is subject to the terms and conditions of the * subcomponent's license, as noted in the LICENSE file. * ****************************************************************************** */ package org.cloudfoundry.identity.uaa.authentication; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.common.util.OAuth2Utils; import org.springframework.security.oauth2.provider.AuthorizationRequest; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * Filter which processes and authenticates a client based on * parameters client_id and client_secret * It sets the authentication to a client only * Oauth2Authentication object as that is expected by * the LoginAuthenticationManager. */ public abstract class AbstractClientParametersAuthenticationFilter implements Filter { public static final String CLIENT_ID = "client_id"; public static final String CLIENT_SECRET = "client_secret"; protected final Log logger = LogFactory.getLog(getClass()); protected AuthenticationManager clientAuthenticationManager; protected AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint(); public AuthenticationManager getClientAuthenticationManager() { return clientAuthenticationManager; } public void setClientAuthenticationManager(AuthenticationManager clientAuthenticationManager) { this.clientAuthenticationManager = clientAuthenticationManager; } /** * @param authenticationEntryPoint the authenticationEntryPoint to set */ public void setAuthenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) { this.authenticationEntryPoint = authenticationEntryPoint; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; Map<String, String> loginInfo = getCredentials(req); String clientId = loginInfo.get(CLIENT_ID); try { wrapClientCredentialLogin(req, res, loginInfo, clientId); } catch (AuthenticationException ex) { logger.debug("Could not authenticate with client credentials."); authenticationEntryPoint.commence(req, res, ex); return; } chain.doFilter(req, res); } public abstract void wrapClientCredentialLogin(HttpServletRequest req, HttpServletResponse res, Map<String, String> loginInfo, String clientId) throws IOException, ServletException; protected void doClientCredentialLogin(HttpServletRequest req, Map<String, String> loginInfo, String clientId) { Authentication clientAuth = performClientAuthentication(req, loginInfo, clientId); SecurityContextHolder.getContext().setAuthentication(clientAuth); } private Map<String, String> getSingleValueMap(HttpServletRequest request) { Map<String, String> map = new HashMap<String, String>(); @SuppressWarnings("unchecked") Map<String, String[]> parameters = request.getParameterMap(); for (String key : parameters.keySet()) { String[] values = parameters.get(key); map.put(key, values != null && values.length > 0 ? values[0] : null); } return map; } private Collection<String> getScope(HttpServletRequest request) { return OAuth2Utils.parseParameterList(request.getParameter("scope")); } private Authentication performClientAuthentication(HttpServletRequest req, Map<String, String> loginInfo, String clientId) { String clientSecret = loginInfo.get(CLIENT_SECRET); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(clientId, clientSecret); authentication.setDetails(new UaaAuthenticationDetails(req, clientId)); try { Authentication auth = clientAuthenticationManager.authenticate(authentication); if (auth == null || !auth.isAuthenticated()) { throw new BadCredentialsException("Client Authentication failed."); } loginInfo.remove(CLIENT_SECRET); AuthorizationRequest authorizationRequest = new AuthorizationRequest(clientId, getScope(req)); authorizationRequest.setRequestParameters(getSingleValueMap(req)); authorizationRequest.setApproved(true); //must set this to true in order for //Authentication.isAuthenticated to return true OAuth2Authentication result = new OAuth2Authentication(authorizationRequest.createOAuth2Request(), null); result.setAuthenticated(true); return result; } catch (AuthenticationException e) { throw new BadCredentialsException(e.getMessage(), e); } catch (Exception e) { logger.debug("Unable to authenticate client: " + clientId, e); throw new BadCredentialsException(e.getMessage(), e); } } private Map<String, String> getCredentials(HttpServletRequest request) { Map<String, String> credentials = new HashMap<>(); credentials.put(CLIENT_ID, request.getParameter(CLIENT_ID)); credentials.put(CLIENT_SECRET, request.getParameter(CLIENT_SECRET)); return credentials; } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }