| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.cxf.fediz.core.handler; |
| |
| import java.security.cert.X509Certificate; |
| import java.util.List; |
| |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| import javax.servlet.http.HttpSession; |
| |
| import org.apache.cxf.fediz.core.FederationConstants; |
| import org.apache.cxf.fediz.core.RequestState; |
| import org.apache.cxf.fediz.core.SAMLSSOConstants; |
| import org.apache.cxf.fediz.core.config.FederationProtocol; |
| import org.apache.cxf.fediz.core.config.FedizContext; |
| import org.apache.cxf.fediz.core.config.SAMLProtocol; |
| import org.apache.cxf.fediz.core.exception.ProcessingException; |
| import org.apache.cxf.fediz.core.processor.FedizProcessor; |
| import org.apache.cxf.fediz.core.processor.FedizProcessorFactory; |
| import org.apache.cxf.fediz.core.processor.FedizRequest; |
| import org.apache.cxf.fediz.core.processor.FedizResponse; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * It is recommended to extend this class and implement the resumeRequest method to continue invoking the originally |
| * requested website. |
| */ |
| public class SigninHandler<T> implements RequestHandler<T> { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(SigninHandler.class); |
| private final FedizContext fedizContext; |
| |
| public SigninHandler(FedizContext fedizContext) { |
| this.fedizContext = fedizContext; |
| } |
| |
| @Override |
| public boolean canHandleRequest(HttpServletRequest request) { |
| if (fedizContext.getProtocol() instanceof FederationProtocol |
| && FederationConstants.ACTION_SIGNIN.equals(request.getParameter(FederationConstants.PARAM_ACTION))) { |
| return true; |
| } else if (fedizContext.getProtocol() instanceof SAMLProtocol |
| && request.getParameter(SAMLSSOConstants.SAML_RESPONSE) != null) { |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public T handleRequest(HttpServletRequest request, HttpServletResponse response) { |
| if ("POST".equals(request.getMethod())) { |
| LOG.debug("Sign-In-Response received"); |
| String responseToken = getResponseToken(request); |
| if (responseToken != null) { |
| LOG.debug("Validating RSTR..."); |
| // process and validate the token |
| try { |
| FedizResponse federationResponse = processSigninRequest(responseToken, request, response); |
| if (!validateAudienceRestrictions(federationResponse.getAudience(), |
| request.getRequestURL().toString())) { |
| return null; |
| } |
| LOG.debug("RSTR validated successfully"); |
| return createPrincipal(request, response, federationResponse); |
| } catch (ProcessingException e) { |
| LOG.error("Federation processing failed: " + e.getMessage()); |
| } |
| } |
| } else { |
| throw new RuntimeException("Incorrect method GET for Sign-In-Response"); |
| } |
| return null; |
| } |
| |
| protected T createPrincipal(HttpServletRequest request, HttpServletResponse response, |
| FedizResponse federationResponse) { |
| return null; |
| } |
| |
| public FedizResponse processSigninRequest(String responseToken, HttpServletRequest req, HttpServletResponse resp) |
| throws ProcessingException { |
| LOG.debug("Process SignIn request"); |
| LOG.debug("token=\n{}", responseToken); |
| |
| FedizRequest federationRequest = new FedizRequest(); |
| |
| String wa = req.getParameter(FederationConstants.PARAM_ACTION); |
| |
| federationRequest.setAction(wa); |
| federationRequest.setResponseToken(responseToken); |
| |
| if (fedizContext.getProtocol() instanceof SAMLProtocol) { |
| String relayState = req.getParameter("RelayState"); |
| federationRequest.setState(relayState); |
| if (relayState != null) { |
| HttpSession session = req.getSession(); |
| federationRequest.setRequestState((RequestState) |
| session.getAttribute(FederationConstants.SESSION_SAVED_REQUEST_STATE_PREFIX + relayState)); |
| session.removeAttribute(FederationConstants.SESSION_SAVED_REQUEST_STATE_PREFIX + relayState); |
| } |
| } |
| federationRequest.setRequest(req); |
| federationRequest.setCerts((X509Certificate[])req.getAttribute("javax.servlet.request.X509Certificate")); |
| |
| FedizProcessor processor = FedizProcessorFactory.newFedizProcessor(fedizContext.getProtocol()); |
| return processor.processRequest(federationRequest, fedizContext); |
| } |
| |
| protected boolean validateAudienceRestrictions(String audience, String requestURL) { |
| // Validate the AudienceRestriction in Security Token (e.g. SAML) |
| // validate against the configured list of audienceURIs |
| List<String> audienceURIs = fedizContext.getAudienceUris(); |
| boolean validAudience = audienceURIs.isEmpty() && audience == null; |
| if (!validAudience && audience != null) { |
| |
| for (String a : audienceURIs) { |
| if (audience.startsWith(a)) { |
| validAudience = true; |
| LOG.debug("Token audience matches with valid URIs."); |
| break; |
| } |
| } |
| |
| if (!validAudience) { |
| LOG.warn("Token AudienceRestriction [{}] doesn't match with specified list of URIs.", audience); |
| LOG.debug("Authenticated URIs are: {}", audienceURIs); |
| } |
| |
| if (LOG.isDebugEnabled() && requestURL != null && requestURL.indexOf(audience) == -1) { |
| LOG.debug("Token AudienceRestriction doesn't match with request URL [{}] [{}]", audience, requestURL); |
| } |
| } |
| return validAudience; |
| } |
| |
| public String getResponseToken(HttpServletRequest request) { |
| String token = null; |
| if (fedizContext.getProtocol() instanceof FederationProtocol) { |
| token = request.getParameter(FederationConstants.PARAM_RESULT); |
| if (token == null) { |
| throw new RuntimeException("Missing required parameter 'wresult'"); |
| } |
| } else if (fedizContext.getProtocol() instanceof SAMLProtocol) { |
| token = request.getParameter(SAMLSSOConstants.SAML_RESPONSE); |
| if (token == null) { |
| throw new RuntimeException("Missing required parameter 'SAMLResponse'"); |
| } |
| } |
| return token; |
| } |
| |
| public String getContextParameter(HttpServletRequest request) { |
| String context = null; |
| if (fedizContext.getProtocol() instanceof FederationProtocol) { |
| context = request.getParameter(FederationConstants.PARAM_CONTEXT); |
| if (fedizContext.isRequestStateValidation() && context == null) { |
| throw new RuntimeException("Missing required parameter 'wctx'"); |
| } |
| } else if (fedizContext.getProtocol() instanceof SAMLProtocol) { |
| context = request.getParameter("RelayState"); |
| if (fedizContext.isRequestStateValidation() && context == null) { |
| throw new RuntimeException("Missing required parameter 'RelayState'"); |
| } |
| } |
| return context; |
| } |
| |
| public FedizContext getFedizContext() { |
| return fedizContext; |
| } |
| } |