blob: 8f5bdec3989baffe839f3d4164cf8084e5df75d4 [file] [log] [blame]
/**
* 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;
}
}