Skip to content

Commit

Permalink
SES-82 ECP Profile implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
vschafer committed Mar 26, 2011
1 parent 305528c commit b0d9e6d
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.opensaml.ws.message.encoder.MessageEncodingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.saml.context.SAMLContextProvider;
import org.springframework.security.saml.context.SAMLMessageContext;
Expand Down Expand Up @@ -135,6 +136,7 @@ public void commence(HttpServletRequest request, HttpServletResponse response, A

if (!ecpRequest && idpSelectionPath != null && !isLoginRequest(request)) {

logger.debug("Initializing IDP selection");
request.getRequestDispatcher(idpSelectionPath).include(request, response);

} else {
Expand All @@ -144,13 +146,19 @@ public void commence(HttpServletRequest request, HttpServletResponse response, A
WebSSOProfileOptions options = getProfileOptions(request, response, context, e);

if (ecpRequest) {

if (webSSOprofileECP == null) {
throw new ServletException("ECP profile isn't available in the entry point, check your configuration");
} else {
logger.debug("Processing ECP request");
webSSOprofileECP.sendAuthenticationRequest(context, options, storage);
}

} else {

logger.debug("Processing WebSSO request");
webSSOprofile.sendAuthenticationRequest(context, options, storage);

}

samlLogger.log(SAMLConstants.AUTH_N_REQUEST, SAMLConstants.SUCCESS, context, e);
Expand All @@ -176,13 +184,13 @@ public void commence(HttpServletRequest request, HttpServletResponse response, A
* @return whether the request comes from an ECP-enabled client or not
*/
protected boolean isECPRequest(HttpServletRequest request) {
String acceptHeader = request.getHeader("Accept");

return acceptHeader != null
String acceptHeader = request.getHeader("Accept");
String paosHeader = request.getHeader(SAMLConstants.PAOS_HTTP_HEADER);
return acceptHeader != null && paosHeader != null
&& acceptHeader.contains(SAMLConstants.PAOS_HTTP_ACCEPT_HEADER)
&& ("ver='" + org.opensaml.common.xml.SAMLConstants.PAOS_NS + "';'"
+ org.opensaml.common.xml.SAMLConstants.SAML20ECP_NS + "'").equals(
request.getHeader(SAMLConstants.PAOS_HTTP_HEADER));
&& paosHeader.contains(org.opensaml.common.xml.SAMLConstants.PAOS_NS)
&& paosHeader.contains(org.opensaml.common.xml.SAMLConstants.SAML20ECP_NS);
}

/**
Expand Down Expand Up @@ -301,6 +309,7 @@ public void setIdpSelectionPath(String idpSelectionPath) {
* @param webSSOprofile profile
*/
@Autowired
@Qualifier("webSSOprofile")
public void setWebSSOprofile(WebSSOProfile webSSOprofile) {
Assert.notNull(webSSOprofile, "WebSSOPRofile can't be null");
this.webSSOprofile = webSSOprofile;
Expand All @@ -310,6 +319,8 @@ public WebSSOProfile getWebSSOprofileECP() {
return webSSOprofileECP;
}

@Autowired(required = false)
@Qualifier("ecpprofile")
public void setWebSSOprofileECP(WebSSOProfile webSSOprofileECP) {
this.webSSOprofileECP = webSSOprofileECP;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ public SAMLMessageContext retrieveMessage(SAMLMessageContext samlContext, SAMLBi
MessageDecoder decoder = binding.getMessageDecoder();
samlContext.setCommunicationProfileId(binding.getCommunicationProfileId());
decoder.decode(samlContext);

if (samlContext.getPeerEntityMetadata() == null) {
throw new MetadataProviderException("Metadata for issuer " + samlContext.getInboundMessageIssuer() + " wasn't found");
}

samlContext.setPeerEntityId(samlContext.getPeerEntityMetadata().getEntityID());
samlContext.setPeerExtendedMetadata(((MetadataManager)samlContext.getMetadataProvider()).getExtendedMetadata(samlContext.getPeerEntityId()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ protected SPSSODescriptor getSPDescriptor(String spId) throws MetadataProviderEx
}

/**
* Method calls the processor and sends the message containted in the context. Subclasses can provide additional
* processing before the message delivery.
* Method calls the processor and sends the message contained in the context. Subclasses can provide additional
* processing before the message delivery. Message is sent using binding defined in the peer entity of the context.
*
* @param context context
* @param sign whether the message should be signed
Expand All @@ -159,6 +159,21 @@ protected void sendMessage(SAMLMessageContext context, boolean sign) throws Meta
processor.sendMessage(context, sign);
}

/**
* Method calls the processor and sends the message contained in the context. Subclasses can provide additional
* processing before the message delivery. Message is sent using the specified binding.
*
* @param context context
* @param sign whether the message should be signed
* @param binding binding to use to send the message
* @throws MetadataProviderException metadata error
* @throws SAMLException SAML encoding error
* @throws org.opensaml.ws.message.encoder.MessageEncodingException message encoding error
*/
protected void sendMessage(SAMLMessageContext context, boolean sign, String binding) throws MetadataProviderException, SAMLException, MessageEncodingException {
processor.sendMessage(context, sign, binding);
}

protected Status getStatus(String code, String statusMessage) {
SAMLObjectBuilder<StatusCode> codeBuilder = (SAMLObjectBuilder<StatusCode>) builderFactory.getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
StatusCode statusCode = codeBuilder.buildObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@ public void sendAuthenticationRequest(SAMLMessageContext context, WebSSOProfileO
SPSSODescriptor spDescriptor = getSPDescriptor(metadata.getHostedSPName());
AssertionConsumerService assertionConsumer = SAMLUtil.getAssertionConsumerForBinding(spDescriptor, SAMLConstants.SAML2_PAOS_BINDING_URI);

SOAPHelper.addHeaderBlock(context, getPAOSRequest(assertionConsumer));
SOAPHelper.addHeaderBlock(context, getECPRequest(options));

if (context.getRelayState() != null) {
SOAPHelper.addHeaderBlock(context, getRelayState(context.getRelayState()));
}

// The last parameter refers to the IdP that should receive the message. However,
// in ECP, we don't know in advance which IdP will be contacted.
AuthnRequest authRequest = getAuthnRequest(options, assertionConsumer, null);
Expand All @@ -73,7 +66,14 @@ public void sendAuthenticationRequest(SAMLMessageContext context, WebSSOProfileO
context.setOutboundMessage(getEnvelope());
context.setOutboundSAMLMessage(authRequest);

sendMessage(context, spDescriptor.isAuthnRequestsSigned());
SOAPHelper.addHeaderBlock(context, getPAOSRequest(assertionConsumer));
SOAPHelper.addHeaderBlock(context, getECPRequest(options));

if (context.getRelayState() != null) {
SOAPHelper.addHeaderBlock(context, getRelayState(context.getRelayState()));
}

sendMessage(context, spDescriptor.isAuthnRequestsSigned(), SAMLConstants.SAML2_PAOS_BINDING_URI);
messageStorage.storeMessage(authRequest.getID(), authRequest);

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package org.springframework.security.saml;

import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.opensaml.common.xml.SAMLConstants;
Expand Down Expand Up @@ -129,6 +130,7 @@ public void testIDPSelection() throws Exception {
expect(request.getRequestDispatcher("/selectIDP")).andReturn(dispatcher);
expect(request.getHeader("Accept")).andReturn(
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
expect(request.getHeader(org.springframework.security.saml.SAMLConstants.PAOS_HTTP_HEADER)).andReturn(null);
dispatcher.include(request, response);

replay(dispatcher);
Expand Down Expand Up @@ -218,7 +220,7 @@ public void testInvalidIDP() throws Exception {
expect(request.getParameter("idp")).andReturn("testIDP");
expect(request.getHeader("Accept")).andReturn(
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");

expect(request.getHeader(org.springframework.security.saml.SAMLConstants.PAOS_HTTP_HEADER)).andReturn(null);
replayMock();
entryPoint.commence(request, response, null);
verifyMock();
Expand All @@ -241,13 +243,49 @@ public void testCorrectIDP() throws Exception {
expect(request.getParameter("idp")).andReturn("http://localhost:8080/opensso");
expect(request.getHeader("Accept")).andReturn(
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
expect(request.getHeader(org.springframework.security.saml.SAMLConstants.PAOS_HTTP_HEADER)).andReturn(null);
ssoProfile.sendAuthenticationRequest((SAMLMessageContext) notNull(), (WebSSOProfileOptions) notNull(), (SAMLMessageStorage) notNull());

replayMock();
entryPoint.commence(request, response, null);
verifyMock();
}

/**
* Test check on whether request supports ECP - it doesn't in this case.
*
* @throws Exception error
*/
@Test
public void testECPRequest_no() throws Exception {

expect(request.getHeader("Accept")).andReturn(
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
expect(request.getHeader(org.springframework.security.saml.SAMLConstants.PAOS_HTTP_HEADER)).andReturn(null);

replayMock();
Assert.assertFalse(entryPoint.isECPRequest(request));
verifyMock();

}

/**
* Test check on whether request supports ECP - it doesn in this case.
*
* @throws Exception error
*/
@Test
public void testECPRequest_yes() throws Exception {

expect(request.getHeader("Accept")).andReturn("text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5, application/vnd.paos+xml");
expect(request.getHeader(org.springframework.security.saml.SAMLConstants.PAOS_HTTP_HEADER)).andReturn("ver='urn:liberty:paos:2003-08'; 'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp'");

replayMock();
Assert.assertTrue(entryPoint.isECPRequest(request));
verifyMock();

}

private void replayMock() {
replay(ssoProfile);
replay(request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@
<bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl"/>

<!-- SAML 2.0 ECP profile -->
<bean id="ecpProfile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"/>
<bean id="ecpprofile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"/>

<!-- SAML 2.0 Logout Profile -->
<bean id="logoutprofile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
<%@ page import="org.springframework.web.context.support.WebApplicationContextUtils" %>
<%@ page import="java.util.Set" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Spring Security SAML Extension - Metadata</title>
</head>
<body>

<h1>IDP selection</h1>

Expand Down Expand Up @@ -38,4 +43,7 @@

<p>
<a href="<c:url value="/saml/web/metadata"/>">Metadata information</a>
</p>
</p>

</body>
</html>

0 comments on commit b0d9e6d

Please sign in to comment.