More work on SSO, now with basic unit tests (which don't work quite yet, but close)
authorlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Sat, 16 Jun 2007 20:36:53 +0000 (20:36 +0000)
committerlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Sat, 16 Jun 2007 20:36:53 +0000 (20:36 +0000)
Convert manner in which profile handlers work
  - Shib common profile handler schema changed into chameleon type schema
  - IdP contains IdP-specific profile handler manager w/ support for Authentication Handlers

git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@2247 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

25 files changed:
resources/META-INF/spring.handlers
resources/META-INF/spring.schemas
resources/classpath/schema/shibboleth-2.0-idp-profile.xsd
resources/conf/protocol.xml
src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationEngine.java
src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationHandler.java
src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationHandlerManager.java [deleted file]
src/edu/internet2/middleware/shibboleth/idp/authn/provider/AbstractAuthenticationHandler.java
src/edu/internet2/middleware/shibboleth/idp/config/profile/IdPProfileHandlerManagerBeanDefinitionParser.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/config/profile/ProfileHandlerGroup.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/config/profile/ProfileHandlerGroupBeanDefinitionParser.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/config/profile/ProfileHandlerNamespaceHandler.java [moved from src/edu/internet2/middleware/shibboleth/idp/config/profile/IdPProfileHandlerNamespaceHandler.java with 56% similarity]
src/edu/internet2/middleware/shibboleth/idp/config/profile/SAML2AttributeQueryProfileHandlerBeanDefinitionParser.java
src/edu/internet2/middleware/shibboleth/idp/config/profile/SAML2SSOProfileHandlerBeanDefinitionParser.java
src/edu/internet2/middleware/shibboleth/idp/config/profile/StatusHandlerBeanDefinitionParser.java
src/edu/internet2/middleware/shibboleth/idp/profile/IdPProfileHandlerManager.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AbstractSAML2ProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/SSOProfileHandler.java
tests/data/conf1/handler.xml [new file with mode: 0644]
tests/data/conf1/internal.xml
tests/data/conf1/protocol.xml [deleted file]
tests/data/conf1/relying-party.xml
tests/data/conf1/service.xml
tests/edu/internet2/middleware/shibboleth/idp/system/conf1/SAML2AttributeQueryTestCase.java
tests/edu/internet2/middleware/shibboleth/idp/system/conf1/SAML2SSOTestCase.java [new file with mode: 0644]

index 8d74ada..ae96c80 100644 (file)
@@ -1,2 +1,2 @@
 urn\:mace\:shibboleth\:2.0\:idp\:services = edu.internet2.middleware.shibboleth.idp.config.service.IdPServicesNamespaceHandler
-urn\:mace\:shibboleth\:2.0\:idp\:profiles = edu.internet2.middleware.shibboleth.idp.config.profile.IdPProfileHandlerNamespaceHandler
\ No newline at end of file
+urn\:mace\:shibboleth\:2.0\:idp\:profile = edu.internet2.middleware.shibboleth.idp.config.profile.ProfileHandlerNamespaceHandler
\ No newline at end of file
index 97411ff..41f59b2 100644 (file)
@@ -1,2 +1,2 @@
 urn\:mace\:shibboleth\:2.0\:idp\:services = schema/shibboleth-2.0-idp-service.xsd
-urn\:mace\:shibboleth\:2.0\:idp\:profiles = schema/shibboleth-2.0-idp-profile.xsd
\ No newline at end of file
+urn\:mace\:shibboleth\:2.0\:idp\:profile = schema/shibboleth-2.0-idp-profile.xsd
\ No newline at end of file
index 432dfcb..c6081a9 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
 
-<schema targetNamespace="urn:mace:shibboleth:2.0:idp:profiles" xmlns="http://www.w3.org/2001/XMLSchema"
-    xmlns:ph="urn:mace:shibboleth:2.0:profile-handler" xmlns:idpph="urn:mace:shibboleth:2.0:idp:profiles"
+<xsd:schema targetNamespace="urn:mace:shibboleth:2.0:idp:profile" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns="urn:mace:shibboleth:2.0:idp:profile" xmlns:service="urn:mace:shibboleth:2.0:services"
     elementFormDefault="qualified">
 
-    <import namespace="urn:mace:shibboleth:2.0:profile-handler"
-        schemaLocation="classpath:/schema/shibboleth-2.0-profile-handler.xsd" />
+    <xsd:include schemaLocation="classpath:/schema/shibboleth-2.0-profile-handler.xsd" />
 
-    <annotation>
-        <documentation>
+    <xsd:import namespace="urn:mace:shibboleth:2.0:services"
+        schemaLocation="classpath:/schema/shibboleth-2.0-services.xsd" />
+
+    <xsd:annotation>
+        <xsd:documentation>
             This schema specifies the configuration options for Shibboleth IdP profile handlers.
-        </documentation>
-    </annotation>
-
-    <complexType name="Status">
-        <annotation>
-            <documentation>Basic handler that returns a general status of the IdP.</documentation>
-        </annotation>
-        <complexContent>
-            <extension base="ph:RequestURIMappedProfileHandlerType" />
-        </complexContent>
-    </complexType>
-
-    <complexType name="SAML2SSO">
-        <annotation>
-            <documentation>Configuration type for SAML 2 Attribute Query profile handlers.</documentation>
-        </annotation>
-        <complexContent>
-            <extension base="idpph:SAML2ProfileHandler">
-                <attribute name="authenticationManagerPath" type="string" default="/AuthnManager">
-                    <annotation>
-                        <documentation>
-                            The context relative path to the authentication manager used by this profile handler.  This should 
-                            match the URL pattern given in the web.xml
-                        </documentation>
-                    </annotation>
-                </attribute>
-                <attribute name="decodingBinding" type="anyURI" default=" urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
-                    <annotation>
-                        <documentation>
+        </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:complexType name="IdPProfileHandlerManager">
+        <xsd:annotation>
+            <xsd:documentation>Definition for the basic Shibboleth profile handler manager service.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexContent>
+            <xsd:extension base="service:ReloadableServiceType" />
+        </xsd:complexContent>
+    </xsd:complexType>
+
+    <xsd:element name="ProfileHandlerGroup">
+        <xsd:annotation>
+            <xsd:documentation>Root of a profile handler configuration file.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element name="ErrorHandler" type="ErrorHandlerType">
+
+                </xsd:element>
+                <xsd:element name="ProfileHandler" type="RequestHandlerType" minOccurs="0"
+                    maxOccurs="unbounded">
+
+                </xsd:element>
+                <xsd:element name="AuthenticationHandler" type="AuthenticationHandlerType" minOccurs="0"
+                    maxOccurs="unbounded">
+
+                </xsd:element>
+            </xsd:sequence>
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:complexType name="Status">
+        <xsd:annotation>
+            <xsd:documentation>Basic handler that returns a general status of the IdP.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexContent>
+            <xsd:extension base="RequestURIMappedProfileHandlerType" />
+        </xsd:complexContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="SAML2SSO">
+        <xsd:annotation>
+            <xsd:documentation>Configuration type for SAML 2 Attribute Query profile handlers.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexContent>
+            <xsd:extension base="SAML2ProfileHandler">
+                <xsd:attribute name="authenticationManagerPath" type="xsd:string" default="/AuthnManager">
+                    <xsd:annotation>
+                        <xsd:documentation>
+                            The context relative path to the authentication manager used by this profile handler. This
+                            should match the URL pattern given in the web.xml
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+                <xsd:attribute name="decodingBinding" type="xsd:anyURI"
+                    default="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
+                    <xsd:annotation>
+                        <xsd:documentation>
                             The URI of the binding used when decoding requests from relying parties.
-                        </documentation>
-                    </annotation>
-                </attribute>
-                <attribute name="encodingBinding" type="anyURI" default=" urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
-                    <annotation>
-                        <documentation>
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+                <xsd:attribute name="encodingBinding" type="xsd:anyURI"
+                    default="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
+                    <xsd:annotation>
+                        <xsd:documentation>
                             The URI of the binding used when encoding responses to relying parties.
-                        </documentation>
-                    </annotation>
-                </attribute>
-            </extension>
-        </complexContent>
-    </complexType>
-
-    <complexType name="SAML2AttributeQuery">
-        <annotation>
-            <documentation>Configuration type for SAML 2 Attribute Query profile handlers.</documentation>
-        </annotation>
-        <complexContent>
-            <extension base="idpph:SAML2ProfileHandler" />
-        </complexContent>
-    </complexType>
-
-    <complexType name="SAML2ProfileHandler" abstract="true">
-        <annotation>
-            <documentation>Base type for SAML 2 profile handlers.</documentation>
-        </annotation>
-        <complexContent>
-            <extension base="idpph:SAMLProfileHandler" />
-        </complexContent>
-    </complexType>
-
-    <complexType name="SAML1AttributeQuery">
-        <annotation>
-            <documentation>Configuration type for SAML 1 Attribute Query profile handlers.</documentation>
-        </annotation>
-        <complexContent>
-            <extension base="idpph:SAML1ProfileHandler" />
-        </complexContent>
-    </complexType>
-
-    <complexType name="SAML1ProfileHandler" abstract="true">
-        <annotation>
-            <documentation>Base type for SAML 1 profile handlers.</documentation>
-        </annotation>
-        <complexContent>
-            <extension base="idpph:SAMLProfileHandler" />
-        </complexContent>
-    </complexType>
-
-    <complexType name="SAMLProfileHandler" abstract="true">
-        <annotation>
-            <documentation>Base type for Shibboleth IdP SAML profile handlers.</documentation>
-        </annotation>
-        <complexContent>
-            <extension base="idpph:IdPProfileHandlerType">
-                <attribute name="messageDecoderFactoryId" type="string" default="shibboleth.MessageDecoderFactory">
-                    <annotation>
-                        <documentation>
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+                <xsd:attribute name="securityPolicyFactoryId" type="xsd:string"
+                    default="shibboleth.SAML2SSOMessageSecurityPolicyFactory">
+                    <xsd:annotation>
+                        <xsd:documentation>
+                            The component ID of the security policy factory to use with the profile handler.
+
+                            This setting should not be changed from its default unless the deployer fully understands
+                            the inter-relationship between IdP components.
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+            </xsd:extension>
+        </xsd:complexContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="SAML2AttributeQuery">
+        <xsd:annotation>
+            <xsd:documentation>Configuration type for SAML 2 Attribute Query profile handlers.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexContent>
+            <xsd:extension base="SAML2ProfileHandler">
+                <xsd:attribute name="securityPolicyFactoryId" type="xsd:string"
+                    default="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactory">
+                    <xsd:annotation>
+                        <xsd:documentation>
+                            The component ID of the security policy factory to use with the profile handler.
+
+                            This setting should not be changed from its default unless the deployer fully understands
+                            the inter-relationship between IdP components.
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+            </xsd:extension>
+        </xsd:complexContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="SAML2ProfileHandler" abstract="true">
+        <xsd:annotation>
+            <xsd:documentation>Base type for SAML 2 profile handlers.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexContent>
+            <xsd:extension base="SAMLProfileHandler" />
+        </xsd:complexContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="SAML1AttributeQuery">
+        <xsd:annotation>
+            <xsd:documentation>Configuration type for SAML 1 Attribute Query profile handlers.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexContent>
+            <xsd:extension base="SAML1ProfileHandler" />
+        </xsd:complexContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="SAML1ProfileHandler" abstract="true">
+        <xsd:annotation>
+            <xsd:documentation>Base type for SAML 1 profile handlers.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexContent>
+            <xsd:extension base="SAMLProfileHandler" />
+        </xsd:complexContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="SAMLProfileHandler" abstract="true">
+        <xsd:annotation>
+            <xsd:documentation>Base type for Shibboleth IdP SAML profile handlers.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexContent>
+            <xsd:extension base="IdPProfileHandlerType">
+                <xsd:attribute name="messageDecoderFactoryId" type="xsd:string"
+                    default="shibboleth.MessageDecoderFactory">
+                    <xsd:annotation>
+                        <xsd:documentation>
                             The component ID of the message decoder to use with the profile handler.
 
                             This setting should not be changed from its default unless the deployer fully understands
                             the inter-relationship between IdP components.
-                        </documentation>
-                    </annotation>
-                </attribute>
-                <attribute name="messageEncoderFactoryId" type="string" default="shibboleth.MessageEncoderFactory">
-                    <annotation>
-                        <documentation>
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+                <xsd:attribute name="messageEncoderFactoryId" type="xsd:string"
+                    default="shibboleth.MessageEncoderFactory">
+                    <xsd:annotation>
+                        <xsd:documentation>
                             The component ID of the message encoder to use with the profile handler.
 
                             This setting should not be changed from its default unless the deployer fully understands
                             the inter-relationship between IdP components.
-                        </documentation>
-                    </annotation>
-                </attribute>
-                <attribute name="idGeneratorId" type="string" default="shibboleth.IdGenerator">
-                    <annotation>
-                        <documentation>
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+                <xsd:attribute name="idGeneratorId" type="xsd:string" default="shibboleth.IdGenerator">
+                    <xsd:annotation>
+                        <xsd:documentation>
                             The component ID of a generator used to generated things like response and assertion IDs.
 
                             This setting should not be changed from its default unless the deployer fully understands
                             the inter-relationship between IdP components.
-                        </documentation>
-                    </annotation>
-                </attribute>
-            </extension>
-        </complexContent>
-    </complexType>
-
-    <complexType name="IdPProfileHandlerType" abstract="true">
-        <annotation>
-            <documentation>Base type for Shibboleth IdP profile handlers.</documentation>
-        </annotation>
-        <complexContent>
-            <extension base="ph:ShibbolethProfileHandlerType" />
-        </complexContent>
-    </complexType>
-
-</schema>
\ No newline at end of file
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+            </xsd:extension>
+        </xsd:complexContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="IdPProfileHandlerType" abstract="true">
+        <xsd:annotation>
+            <xsd:documentation>Base type for IdP profile handlers.</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexContent>
+            <xsd:extension base="ShibbolethProfileHandlerType" />
+        </xsd:complexContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="AuthenticationHandlerType" abstract="true">
+    
+    </xsd:complexType>
+    
+</xsd:schema>
\ No newline at end of file
index b84a6d8..10f9fe6 100644 (file)
@@ -1,10 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
-<ProfileHandlerGroup xmlns="urn:mace:shibboleth:2.0:profile-handler"
-                 xmlns:idpProfile="urn:mace:shibboleth:2.0:idp:profiles"
+<ProfileHandlerGroup xmlns="urn:mace:shibboleth:2.0:idp:profile"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-                 xsi:schemaLocation="urn:mace:shibboleth:2.0:profile-handler classpath:/schema/shibboleth-2.0-profile-handler.xsd
-                                     urn:mace:shibboleth:2.0:idp:profiles classpath:/schema/shibboleth-2.0-idp-profile.xsd">
+                 xsi:schemaLocation="urn:mace:shibboleth:2.0:idp:profile classpath:/schema/shibboleth-2.0-idp-profile.xsd">
 
     <ErrorHandler xsi:type="JSPErrorHandler" jspPagePath="/error.jsp" />
 
index 0b27f33..f921dfa 100644 (file)
@@ -33,8 +33,8 @@ import org.joda.time.DateTime;
 import org.opensaml.xml.util.DatatypeHelper;
 import org.opensaml.xml.util.Pair;
 
-import edu.internet2.middleware.shibboleth.common.profile.ProfileHandlerManager;
 import edu.internet2.middleware.shibboleth.common.session.SessionManager;
+import edu.internet2.middleware.shibboleth.idp.profile.IdPProfileHandlerManager;
 import edu.internet2.middleware.shibboleth.idp.session.AuthenticationMethodInformation;
 import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
 import edu.internet2.middleware.shibboleth.idp.session.Session;
@@ -46,6 +46,9 @@ import edu.internet2.middleware.shibboleth.idp.session.impl.ServiceInformationIm
  */
 public class AuthenticationEngine extends HttpServlet {
 
+    /** Serial version UID. */
+    private static final long serialVersionUID = 8494202791991613148L;
+
     /** Class logger. */
     private static final Logger LOG = Logger.getLogger(AuthenticationEngine.class);
 
@@ -54,8 +57,8 @@ public class AuthenticationEngine extends HttpServlet {
      * 
      * @return manager used to retrieve handlers for requests
      */
-    public ProfileHandlerManager getProfileHandlerManager() {
-        return (ProfileHandlerManager) getServletContext().getAttribute("handlerManager");
+    public IdPProfileHandlerManager getProfileHandlerManager() {
+        return (IdPProfileHandlerManager) getServletContext().getAttribute("handlerManager");
     }
 
     /**
@@ -69,15 +72,6 @@ public class AuthenticationEngine extends HttpServlet {
     }
 
     /**
-     * Gets the authentication handler manager used by this engine.
-     * 
-     * @return authentication handler manager used by this engine
-     */
-    public AuthenticationHandlerManager getAuthenticationHandlerManager() {
-        return (AuthenticationHandlerManager) getServletContext().getAttribute("authenticationHandlerManager");
-    }
-
-    /**
      * Returns control back to the authentication engine.
      * 
      * @param httpRequest current http request
@@ -218,7 +212,7 @@ public class AuthenticationEngine extends HttpServlet {
         if (LOG.isDebugEnabled()) {
             LOG.debug("Selecting appropriate authentication method for request.");
         }
-        Pair<String, AuthenticationHandler> handler = getAuthenticationHandlerManager().getAuthenticationHandler(
+        Pair<String, AuthenticationHandler> handler = getProfileHandlerManager().getAuthenticationHandler(
                 loginContext);
 
         if (handler == null) {
index 337dde3..e25443c 100644 (file)
@@ -16,6 +16,8 @@
 
 package edu.internet2.middleware.shibboleth.idp.authn;
 
+import java.util.List;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -45,6 +47,13 @@ public interface AuthenticationHandler {
     public static final String AUTHENTICATION_ERROR_KEY = "authnError";
 
     /**
+     * Gets the list of authentication methods this handler supports.
+     * 
+     * @return authentication methods this handler supports
+     */
+    public List<String> getSupportedAuthenticationMethods();
+    
+    /**
      * Gets the length of time, in milliseconds, after which a user authenticated by this handler should be
      * re-authenticated.
      * 
diff --git a/src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationHandlerManager.java b/src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationHandlerManager.java
deleted file mode 100644 (file)
index f7053d1..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
- *
- * 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 edu.internet2.middleware.shibboleth.idp.authn;
-
-import java.util.Map;
-
-import org.opensaml.xml.util.Pair;
-
-/**
- * Manager for registering and retrieving authentication handlers.
- */
-public interface AuthenticationHandlerManager {
-
-    /**
-     * Gets the registered authentication handlers.
-     * 
-     * @return registered authentication handlers
-     */
-    public Map<String, AuthenticationHandler> getAuthenticationHandlers();
-
-    /**
-     * Gets the authentication handler appropriate for the given loging context. The mechanism used to determine the
-     * "appropriate" handler is implementation specific.
-     * 
-     * @param loginContext current login context
-     * 
-     * @return authentication method URI and handler appropriate for given login context
-     */
-    public Pair<String, AuthenticationHandler> getAuthenticationHandler(LoginContext loginContext);
-}
\ No newline at end of file
index b49a925..70692ff 100644 (file)
 
 package edu.internet2.middleware.shibboleth.idp.authn.provider;
 
-import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.log4j.Logger;
-
 import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationHandler;
-import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
 
 /**
  * Base class for authentication handlers.
  */
 public abstract class AbstractAuthenticationHandler implements AuthenticationHandler {
-
-    /** Class logger. */
-    private final Logger log = Logger.getLogger(AbstractAuthenticationHandler.class);
+    
+    /** Authentication methods this handler supports. */
+    private ArrayList<String> supportedAuthenticationMethods;
 
     /** Length of time, in milliseconds, after which a user should be re-authenticated. */
     private long authenticationDuration;
@@ -44,6 +40,16 @@ public abstract class AbstractAuthenticationHandler implements AuthenticationHan
 
     /** Whether this handler supports passive authentication. */
     private boolean supportsPassive;
+    
+    /** Constructor. */
+    protected AbstractAuthenticationHandler(){
+        supportedAuthenticationMethods = new ArrayList<String>();
+    }
+    
+    /** {@inheritDoc} */
+    public List<String> getSupportedAuthenticationMethods() {
+        return supportedAuthenticationMethods;
+    }
 
     /** {@inheritDoc} */
     public long getAuthenticationDuration() {
diff --git a/src/edu/internet2/middleware/shibboleth/idp/config/profile/IdPProfileHandlerManagerBeanDefinitionParser.java b/src/edu/internet2/middleware/shibboleth/idp/config/profile/IdPProfileHandlerManagerBeanDefinitionParser.java
new file mode 100644 (file)
index 0000000..0bf0688
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * 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 edu.internet2.middleware.shibboleth.idp.config.profile;
+
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Element;
+
+import edu.internet2.middleware.shibboleth.common.config.service.AbstractReloadableServiceBeanDefinitionParser;
+import edu.internet2.middleware.shibboleth.idp.profile.IdPProfileHandlerManager;
+
+/**
+ * Spring bean definition parser for {@link IdPProfileHandlerManager}s.
+ */
+public class IdPProfileHandlerManagerBeanDefinitionParser extends AbstractReloadableServiceBeanDefinitionParser {
+
+    /** Schema type. */
+    public static final QName SCHEMA_TYPE = new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "IdPProfileHandlerManager");
+
+    /** {@inheritDoc} */
+    protected Class getBeanClass(Element arg0) {
+        return IdPProfileHandlerManager.class;
+    }
+}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/idp/config/profile/ProfileHandlerGroup.java b/src/edu/internet2/middleware/shibboleth/idp/config/profile/ProfileHandlerGroup.java
new file mode 100644 (file)
index 0000000..459d3b8
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * 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 edu.internet2.middleware.shibboleth.idp.config.profile;
+
+import java.util.List;
+
+import edu.internet2.middleware.shibboleth.common.profile.AbstractErrorHandler;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationHandler;
+
+/**
+ * Container for a single profile handler group configuration.
+ */
+public class ProfileHandlerGroup {
+
+    /** Error handler for the group. */
+    private AbstractErrorHandler errorHandler;
+
+    /** List of profile handlers for the group. */
+    private List<ProfileHandler> profileHandlers;
+    
+    /** List of authentication handlers for the group. */
+    private List<AuthenticationHandler> authenticationHandlers;
+
+    /**
+     * Gets the error handler for the group.
+     * 
+     * @return error handler for the group
+     */
+    public AbstractErrorHandler getErrorHandler() {
+        return errorHandler;
+    }
+
+    /**
+     * Sets the error handler for the group.
+     * 
+     * @param handler error handler for the group
+     */
+    public void setErrorHandler(AbstractErrorHandler handler) {
+        errorHandler = handler;
+    }
+
+    /**
+     * Gets the profile handlers for the group.
+     * 
+     * @return profile handlers for the group
+     */
+    public List<ProfileHandler> getProfileHandlers() {
+        return profileHandlers;
+    }
+
+    /**
+     * Sets the profile handlers for the group.
+     * 
+     * @param handlers profile handlers for the group
+     */
+    public void setProfileHandlers(List<ProfileHandler> handlers) {
+        profileHandlers = handlers;
+    }
+    
+    /**
+     * Gets the authentication handlers for the group.
+     * 
+     * @return authentication handlers for the group
+     */
+    public List<AuthenticationHandler> getAuthenticationHandlers() {
+        return authenticationHandlers;
+    }
+
+    /**
+     * Sets the authentication handlers for the group.
+     * 
+     * @param handlers authentication handlers for the group
+     */
+    public void setAuthenticationHandlers(List<AuthenticationHandler> handlers) {
+        authenticationHandlers = handlers;
+    }
+}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/idp/config/profile/ProfileHandlerGroupBeanDefinitionParser.java b/src/edu/internet2/middleware/shibboleth/idp/config/profile/ProfileHandlerGroupBeanDefinitionParser.java
new file mode 100644 (file)
index 0000000..bb683da
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * 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 edu.internet2.middleware.shibboleth.idp.config.profile;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.opensaml.xml.util.XMLHelper;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.w3c.dom.Element;
+
+import edu.internet2.middleware.shibboleth.common.config.SpringConfigurationUtils;
+
+/**
+ * Spring bean definition parser for profile handler root element.
+ */
+public class ProfileHandlerGroupBeanDefinitionParser extends AbstractBeanDefinitionParser {
+
+    /** Schema type name. */
+    public static final QName SCHEMA_TYPE = new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "ProfileHandlerGroup");
+
+    /** {@inheritDoc} */
+    protected AbstractBeanDefinition parseInternal(Element config, ParserContext context) {
+        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ProfileHandlerGroup.class);
+
+        Map<QName, List<Element>> configChildren = XMLHelper.getChildElements(config);
+        List<Element> children;
+
+        children = configChildren.get(new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "ErrorHandler"));
+        builder.addPropertyValue("errorHandler", SpringConfigurationUtils.parseCustomElement(children.get(0), context));
+
+        children = configChildren.get(new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "ProfileHandler"));
+        builder.addPropertyValue("profileHandlers", SpringConfigurationUtils.parseCustomElements(children, context));
+
+        children = configChildren.get(new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "AuthenticationHandler"));
+        builder.addPropertyValue("authenticationHandlers", SpringConfigurationUtils.parseCustomElements(children,
+                context));
+
+        return builder.getBeanDefinition();
+    }
+
+    /** {@inheritDoc} */
+    protected boolean shouldGenerateId() {
+        return true;
+    }
+}
\ No newline at end of file
 
 package edu.internet2.middleware.shibboleth.idp.config.profile;
 
+import javax.xml.namespace.QName;
+
 import edu.internet2.middleware.shibboleth.common.config.BaseSpringNamespaceHandler;
+import edu.internet2.middleware.shibboleth.common.config.profile.JSPErrorHandlerBeanDefinitionParser;
+import edu.internet2.middleware.shibboleth.common.config.profile.VelocityErrorHandlerBeanDefinitionParser;
 
 /**
- * Spring namespace handler for IdP profile handlers.
+ * Spring namespace handler for profile handler configurations.
  */
-public class IdPProfileHandlerNamespaceHandler extends BaseSpringNamespaceHandler {
+public class ProfileHandlerNamespaceHandler extends BaseSpringNamespaceHandler {
 
-    /** IdP profile handler namespace URI. */
-    public static final String NAMESPACE = "urn:mace:shibboleth:2.0:idp:profiles";
+    /** Namespace URI. */
+    public static final String NAMESPACE = "urn:mace:shibboleth:2.0:idp:profile";
 
     /** {@inheritDoc} */
     public void init() {
+        registerBeanDefinitionParser(IdPProfileHandlerManagerBeanDefinitionParser.SCHEMA_TYPE,
+                new IdPProfileHandlerManagerBeanDefinitionParser());
+
+        registerBeanDefinitionParser(ProfileHandlerGroupBeanDefinitionParser.SCHEMA_TYPE,
+                new ProfileHandlerGroupBeanDefinitionParser());
+
+        registerBeanDefinitionParser(new QName(NAMESPACE, JSPErrorHandlerBeanDefinitionParser.ELEMENT_NAME),
+                new JSPErrorHandlerBeanDefinitionParser());
+
+        registerBeanDefinitionParser(new QName(NAMESPACE, VelocityErrorHandlerBeanDefinitionParser.ELEMENT_NAME),
+                new VelocityErrorHandlerBeanDefinitionParser());
+
         registerBeanDefinitionParser(StatusHandlerBeanDefinitionParser.SCHEMA_TYPE,
                 new StatusHandlerBeanDefinitionParser());
 
index ff81dc4..58df12d 100644 (file)
@@ -18,6 +18,8 @@ package edu.internet2.middleware.shibboleth.idp.config.profile;
 
 import javax.xml.namespace.QName;
 
+import org.opensaml.xml.util.DatatypeHelper;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.w3c.dom.Element;
 
 import edu.internet2.middleware.shibboleth.idp.profile.saml2.AttributeQueryProfileHandler;
@@ -29,11 +31,19 @@ public class SAML2AttributeQueryProfileHandlerBeanDefinitionParser extends
         AbstractSAML2ProfileHandlerBeanDefinitionParser {
 
     /** Schema type. */
-    public static final QName SCHEMA_TYPE = new QName(IdPProfileHandlerNamespaceHandler.NAMESPACE,
+    public static final QName SCHEMA_TYPE = new QName(ProfileHandlerNamespaceHandler.NAMESPACE,
             "SAML2AttributeQuery");
 
     /** {@inheritDoc} */
     protected Class getBeanClass(Element arg0) {
         return AttributeQueryProfileHandler.class;
     }
+    
+    /** {@inheritDoc} */
+    protected void doParse(Element config, BeanDefinitionBuilder builder) {
+        super.doParse(config, builder);
+
+        builder.addPropertyReference("securityPolicyFactory", DatatypeHelper.safeTrimOrNullString(config
+                .getAttributeNS(null, "securityPolicyFactoryId")));
+    }
 }
\ No newline at end of file
index 9bc22df..03dab83 100644 (file)
@@ -30,7 +30,7 @@ import edu.internet2.middleware.shibboleth.idp.profile.saml2.SSOProfileHandler;
 public class SAML2SSOProfileHandlerBeanDefinitionParser extends AbstractSAML2ProfileHandlerBeanDefinitionParser {
 
     /** Schema type. */
-    public static final QName SCHEMA_TYPE = new QName(IdPProfileHandlerNamespaceHandler.NAMESPACE, "SAML2SSO");
+    public static final QName SCHEMA_TYPE = new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "SAML2SSO");
 
     /** {@inheritDoc} */
     protected Class getBeanClass(Element arg0) {
@@ -47,5 +47,8 @@ public class SAML2SSOProfileHandlerBeanDefinitionParser extends AbstractSAML2Pro
         builder.addConstructorArg(DatatypeHelper.safeTrimOrNullString(config.getAttributeNS(null, "decodingBinding")));
 
         builder.addConstructorArg(DatatypeHelper.safeTrimOrNullString(config.getAttributeNS(null, "encodingBinding")));
+
+        builder.addPropertyReference("securityPolicyFactory", DatatypeHelper.safeTrimOrNullString(config
+                .getAttributeNS(null, "securityPolicyFactoryId")));
     }
 }
\ No newline at end of file
index 3fad3f7..c966791 100644 (file)
@@ -27,9 +27,9 @@ import edu.internet2.middleware.shibboleth.idp.profile.StatusProfileHandler;
  * Spring bean definition parser for {@link StatusProfileHandler}s.
  */
 public class StatusHandlerBeanDefinitionParser extends AbstractRequestURIMappedProfileHandlerBeanDefinitionParser {
-    
+
     /** Schema type. */
-    public static final QName SCHEMA_TYPE = new QName(IdPProfileHandlerNamespaceHandler.NAMESPACE, "Status");
+    public static final QName SCHEMA_TYPE = new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "Status");
 
     /** {@inheritDoc} */
     protected Class getBeanClass(Element arg0) {
diff --git a/src/edu/internet2/middleware/shibboleth/idp/profile/IdPProfileHandlerManager.java b/src/edu/internet2/middleware/shibboleth/idp/profile/IdPProfileHandlerManager.java
new file mode 100644 (file)
index 0000000..f625e19
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * 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 edu.internet2.middleware.shibboleth.idp.profile;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.concurrent.locks.Lock;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.log4j.Logger;
+import org.opensaml.util.resource.Resource;
+import org.opensaml.util.resource.ResourceException;
+import org.opensaml.xml.util.Pair;
+import org.springframework.context.ApplicationContext;
+
+import edu.internet2.middleware.shibboleth.common.config.BaseReloadableService;
+import edu.internet2.middleware.shibboleth.common.profile.AbstractErrorHandler;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileHandlerManager;
+import edu.internet2.middleware.shibboleth.common.profile.provider.AbstractRequestURIMappedProfileHandler;
+import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationHandler;
+import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
+
+/**
+ * Implementation of a {@link ProfileHandlerManager} that maps the request path, without the servlet context, to a
+ * profile handler and adds support for authentication handlers.
+ */
+public class IdPProfileHandlerManager extends BaseReloadableService implements ProfileHandlerManager {
+
+    /** URI of the default authentication method. */
+    public static final String DEFAULT_AUTHEN_METHOD_URI = "urn:mace:shibboleth:2.0:idp:authentication:method:default";
+
+    /** Class logger. */
+    private final Logger log = Logger.getLogger(IdPProfileHandlerManager.class);
+
+    /** Handler used for errors. */
+    private AbstractErrorHandler errorHandler;
+
+    /** Map of request paths to profile handlers. */
+    private Map<String, AbstractRequestURIMappedProfileHandler> profileHandlers;
+
+    /** Map of authentication methods to authentication handlers. */
+    private Map<String, AuthenticationHandler> authenticationHandlers;
+
+    /**
+     * Constructor. Configuration resources are not monitored for changes.
+     * 
+     * @param configurations configuration resources for this service
+     */
+    public IdPProfileHandlerManager(List<Resource> configurations) {
+        super(configurations);
+        profileHandlers = new HashMap<String, AbstractRequestURIMappedProfileHandler>();
+        authenticationHandlers = new HashMap<String, AuthenticationHandler>();
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param timer timer resource polling tasks are scheduled with
+     * @param configurations configuration resources for this service
+     * @param pollingFrequency the frequency, in milliseconds, to poll the policy resources for changes, must be greater
+     *            than zero
+     */
+    public IdPProfileHandlerManager(List<Resource> configurations, Timer timer, long pollingFrequency) {
+        super(timer, configurations, pollingFrequency);
+        profileHandlers = new HashMap<String, AbstractRequestURIMappedProfileHandler>();
+        authenticationHandlers = new HashMap<String, AuthenticationHandler>();
+    }
+
+    /** {@inheritDoc} */
+    public AbstractErrorHandler getErrorHandler() {
+        return errorHandler;
+    }
+
+    /**
+     * Sets the error handler.
+     * 
+     * @param handler error handler
+     */
+    public void setErrorHandler(AbstractErrorHandler handler) {
+        if (handler == null) {
+            throw new IllegalArgumentException("Error handler may not be null");
+        }
+        errorHandler = handler;
+    }
+
+    /** {@inheritDoc} */
+    public ProfileHandler getProfileHandler(ServletRequest request) {
+        ProfileHandler handler;
+
+        String requestPath = ((HttpServletRequest) request).getPathInfo();
+        if (log.isDebugEnabled()) {
+            log.debug("Looking up profile handler for request path: " + requestPath);
+        }
+        Lock readLock = getReadWriteLock().readLock();
+        readLock.lock();
+        handler = profileHandlers.get(requestPath);
+        readLock.unlock();
+
+        if (handler != null) {
+            if (log.isDebugEnabled()) {
+                log.debug("Located profile handler of the following type for request path " + requestPath + ": "
+                        + handler.getClass().getName());
+            }
+        } else {
+            if (log.isDebugEnabled()) {
+                log.debug("No profile handler registered for request path " + requestPath);
+            }
+        }
+        return handler;
+    }
+
+    /**
+     * Gets the registered profile handlers.
+     * 
+     * @return registered profile handlers
+     */
+    public Map<String, AbstractRequestURIMappedProfileHandler> getProfileHandlers() {
+        return profileHandlers;
+    }
+
+    /**
+     * Gets the authentication handler appropriate for the given loging context. The mechanism used to determine the
+     * "appropriate" handler is implementation specific.
+     * 
+     * @param loginContext current login context
+     * 
+     * @return authentication method URI and handler appropriate for given login context
+     */
+    public Pair<String, AuthenticationHandler> getAuthenticationHandler(LoginContext loginContext) {
+        List<String> requestedMethods = loginContext.getRequestedAuthenticationMethods();
+        if (requestedMethods != null) {
+            AuthenticationHandler candidateHandler;
+            for (String requestedMethod : requestedMethods) {
+                candidateHandler = authenticationHandlers.get(requestedMethod);
+                if (candidateHandler != null) {
+                    if (loginContext.getPassiveAuth() && candidateHandler.supportsPassive()) {
+                        return new Pair<String, AuthenticationHandler>(requestedMethod, candidateHandler);
+                    }
+                }
+            }
+        }
+
+        Pair<String, AuthenticationHandler> authenticationHandler = new Pair<String, AuthenticationHandler>(
+                DEFAULT_AUTHEN_METHOD_URI, authenticationHandlers.get(DEFAULT_AUTHEN_METHOD_URI));
+        return authenticationHandler;
+    }
+
+    /**
+     * Gets the registered authentication handlers.
+     * 
+     * @return registered authentication handlers
+     */
+    public Map<String, AuthenticationHandler> getAuthenticationHandlers() {
+        return authenticationHandlers;
+    }
+
+    /** {@inheritDoc} */
+    protected void newContextCreated(ApplicationContext newServiceContext) throws ResourceException {
+        if (log.isDebugEnabled()) {
+            log.debug("Loading new configuration into service");
+        }
+        String[] errorBeanNames = newServiceContext.getBeanNamesForType(AbstractErrorHandler.class);
+        String[] profileBeanNames = newServiceContext.getBeanNamesForType(AbstractRequestURIMappedProfileHandler.class);
+        String[] authnBeanNames = newServiceContext.getBeanNamesForType(AuthenticationHandler.class);
+
+        Lock writeLock = getReadWriteLock().writeLock();
+        writeLock.lock();
+
+        errorHandler = (AbstractErrorHandler) newServiceContext.getBean(errorBeanNames[0]);
+        if (log.isDebugEnabled()) {
+            log.debug("Loaded new error handler of type: " + errorHandler.getClass().getName());
+        }
+
+        profileHandlers.clear();
+        if (log.isDebugEnabled()) {
+            log.debug(profileBeanNames.length + " profile handlers loaded");
+        }
+        AbstractRequestURIMappedProfileHandler profileHandler;
+        for (String profileBeanName : profileBeanNames) {
+            profileHandler = (AbstractRequestURIMappedProfileHandler) newServiceContext.getBean(profileBeanName);
+            for (String requestPath : profileHandler.getRequestPaths()) {
+                profileHandlers.put(requestPath, profileHandler);
+                if (log.isDebugEnabled()) {
+                    log.debug("Request path " + requestPath + " mapped to profile handler of type: "
+                            + profileHandler.getClass().getName());
+                }
+            }
+        }
+
+        authenticationHandlers.clear();
+        if (log.isDebugEnabled()) {
+            log.debug(authnBeanNames.length + " authentication handlers loaded");
+        }
+        AuthenticationHandler authnHandler;
+        for (String authnBeanName : authnBeanNames) {
+            authnHandler = (AuthenticationHandler) newServiceContext.getBean(authnBeanName);
+            for (String authnMethod : authnHandler.getSupportedAuthenticationMethods()) {
+                authenticationHandlers.put(authnMethod, authnHandler);
+                if (log.isDebugEnabled()) {
+                    log.debug("Authentication method " + authnMethod + " mapped to authentication handler of type: "
+                            + authnHandler.getClass().getName());
+                }
+            }
+        }
+
+        writeLock.unlock();
+    }
+}
\ No newline at end of file
index c50da3e..3b79a12 100644 (file)
@@ -500,6 +500,15 @@ public abstract class AbstractSAML2ProfileHandler extends AbstractSAMLProfileHan
      */
     protected void resolvePrincipal(SAML2ProfileRequestContext requestContext) throws ProfileException {
         AbstractSAML2ProfileConfiguration profileConfiguration = requestContext.getProfileConfiguration();
+        if (profileConfiguration == null) {
+            log.error("Unable to resolve principal, no SAML 2 profile configuration for relying party "
+                    + requestContext.getRelyingPartyId());
+            requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, StatusCode.REQUEST_DENIED_URI,
+                    "Error resolving principal"));
+            throw new ProfileException(
+                    "Unable to resolve principal, no SAML 2 profile configuration for relying party "
+                            + requestContext.getRelyingPartyId());
+        }
         SAML2AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
 
         if (log.isDebugEnabled()) {
index 3f2fd02..ebbbcd0 100644 (file)
@@ -303,6 +303,8 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
         SSORequestContext requestContext = new SSORequestContext(request, response);
 
         try {
+            requestContext.setLoginContext(loginContext);
+            
             String relyingPartyId = loginContext.getRelyingPartyId();
             AuthnRequest authnRequest = loginContext.getAuthenticationRequest();
 
@@ -316,6 +318,8 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
             requestContext.setAssertingPartyId(requestContext.getRelyingPartyConfiguration().getProviderId());
 
             requestContext.setAssertingPartyRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+            
+            requestContext.setPrincipalName(loginContext.getPrincipalName());
 
             requestContext.setProfileConfiguration((SSOConfiguration) rpConfig
                     .getProfileConfiguration(SSOConfiguration.PROFILE_ID));
diff --git a/tests/data/conf1/handler.xml b/tests/data/conf1/handler.xml
new file mode 100644 (file)
index 0000000..97916b5
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<ProfileHandlerGroup xmlns="urn:mace:shibboleth:2.0:idp:profile" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="urn:mace:shibboleth:2.0:idp:profile classpath:/schema/shibboleth-2.0-idp-profile.xsd">
+
+    <ErrorHandler xsi:type="JSPErrorHandler" jspPagePath="/error.jsp" />
+
+    <ProfileHandler xsi:type="Status">
+        <RequestPath>/shibboleth/IdP/status</RequestPath>
+    </ProfileHandler>
+
+    <ProfileHandler xsi:type="SAML2AttributeQuery"
+        securityPolicyFactoryId="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactoryNoIssuerAuth">
+        <RequestPath>/IdP/saml2/SOAP/AttributeQueryNoAuth</RequestPath>
+    </ProfileHandler>
+
+    <ProfileHandler xsi:type="SAML2AttributeQuery"
+        securityPolicyFactoryId="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactoryIssuerAuth">
+        <RequestPath>/IdP/saml2/SOAP/AttributeQuery</RequestPath>
+    </ProfileHandler>
+    
+    <ProfileHandler xsi:type="SAML2SSO"
+        securityPolicyFactoryId="shibboleth.SAML2SSOMessageSecurityPolicyFactoryNoIssuerAuth">
+        <RequestPath>/IdP/saml2/SSONoAuth</RequestPath>
+    </ProfileHandler>
+
+    <ProfileHandler xsi:type="SAML2SSO"
+        securityPolicyFactoryId="shibboleth.SAML2SSOMessageSecurityPolicyFactoryIssuerAuth">
+        <RequestPath>/IdP/saml2/SSO</RequestPath>
+    </ProfileHandler>
+
+</ProfileHandlerGroup>
\ No newline at end of file
index 08b586e..f2cf393 100644 (file)
         <property name="namespaceAware" value="true" />
     </bean>
 
+    <bean id="shibboleth.SAML2SSOMessageSecurityPolicyFactoryNoIssuerAuth"
+          parent="shibboleth.SAML2SSOMessageSecurityPolicyFactoryIssuerAuth">
+        <property name="requiredAuthenticatedIssuer" value="false" />
+    </bean>
+    
+    <bean id="shibboleth.SAML2SSOMessageSecurityPolicyFactoryIssuerAuth"
+          parent="shibboleth.BaseSAML2SecurityPolicyFactory">
+        <property name="issuerRole">
+            <bean id="shibboleth.SAML2SSORole" class="javax.xml.namespace.QName">
+                <constructor-arg value="urn:oasis:names:tc:SAML:2.0:metadata" />
+                <constructor-arg value="SPSSODescriptor" />
+            </bean>
+        </property>
+    </bean>
+    
     <bean id="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactoryNoIssuerAuth"
-          class="org.opensaml.common.binding.security.SAMLSecurityPolicyFactory">
+          parent="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactoryIssuerAuth">
+        <property name="requiredAuthenticatedIssuer" value="false" />
+    </bean>
+    
+    <bean id="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactoryIssuerAuth"
+          parent="shibboleth.BaseSAML2SecurityPolicyFactory">
         <property name="issuerRole">
             <bean id="shibboleth.SAML2AttributeQueryRole" class="javax.xml.namespace.QName">
                 <constructor-arg value="urn:oasis:names:tc:SAML:2.0:metadata" />
                 <constructor-arg value="SPSSODescriptor" />
             </bean>
         </property>
+    </bean>
+    
+    <bean id="shibboleth.BaseSAML2SecurityPolicyFactory" abstract="true" class="org.opensaml.common.binding.security.SAMLSecurityPolicyFactory">
         <property name="issuerProtocol" value="urn:oasis:names:tc:SAML:2.0:protocol" />
         <property name="policyRuleFactories">
             <list>
                 <ref bean="shibboleth.MessageIssueInstantRuleFactory" />
             </list>
         </property>
-        <property name="requiredAuthenticatedIssuer" value="false" />
-    </bean>
-    
-    <bean id="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactoryIssuerAuth"
-          class="org.opensaml.common.binding.security.SAMLSecurityPolicyFactory"
-          parent="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactoryNoIssuerAuth">
         <property name="requiredAuthenticatedIssuer" value="true" />
     </bean>
     
diff --git a/tests/data/conf1/protocol.xml b/tests/data/conf1/protocol.xml
deleted file mode 100644 (file)
index 0aa0a65..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<ProfileHandlerGroup xmlns="urn:mace:shibboleth:2.0:profile-handler"
-    xmlns:idpProfile="urn:mace:shibboleth:2.0:idp:profiles" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="urn:mace:shibboleth:2.0:profile-handler classpath:/schema/shibboleth-2.0-profile-handler.xsd
-                                     urn:mace:shibboleth:2.0:idp:profiles classpath:/schema/shibboleth-2.0-idp-profile.xsd">
-
-    <ErrorHandler xsi:type="JSPErrorHandler" jspPagePath="/error.jsp" />
-
-    <ProfileHandler xsi:type="idpProfile:Status">
-        <RequestPath>/shibboleth/IdP/status</RequestPath>
-    </ProfileHandler>
-
-    <ProfileHandler xsi:type="idpProfile:SAML2AttributeQuery"
-        securityPolicyFactoryId="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactoryNoIssuerAuth">
-        <RequestPath>/IdP/saml2/SOAP/AttributeQueryNoAuth</RequestPath>
-    </ProfileHandler>
-
-    <ProfileHandler xsi:type="idpProfile:SAML2AttributeQuery"
-        securityPolicyFactoryId="shibboleth.SAML2AttributeQueryMessageSecurityPolicyFactoryIssuerAuth">
-        <RequestPath>/IdP/saml2/SOAP/AttributeQuery</RequestPath>
-    </ProfileHandler>
-
-    <!--
-        <ProfileHandler xsi:type="idpProfile:SAML2SSO">
-        <RequestPath>/IdP/saml2/HTTP/SSO</RequestPath>
-        </ProfileHandler>
-        
-        <ProfileHandler xsi:type="idpProfile:SAML2AttributeQuery">
-        <RequestPath>/IdP/saml2/SOAP/attribute</RequestPath>
-        </ProfileHandler>
-    -->
-
-</ProfileHandlerGroup>
\ No newline at end of file
index 6ad4227..f0b0660 100644 (file)
@@ -23,7 +23,8 @@
     
     <RelyingParty id="urn:example.org:unitTestFed"
                   provider="http://example.org/IdP">
-        <ProfileConfiguration xsi:type="saml:SAML2AttributesQueryProfile" />
+        <ProfileConfiguration xsi:type="saml:SAML2AttributeQueryProfile" />
+        <ProfileConfiguration xsi:type="saml:SAML2SSOProfile" />
     </RelyingParty>
     
     <MetadataProvider id="UnitTestConf1" xsi:type="InlineMetadataProvider" xmlns="urn:mace:shibboleth:2.0:metadata">
index 09c65f8..efaafa8 100644 (file)
@@ -1,33 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <IdPConfig xmlns="urn:mace:shibboleth:2.0:idp:services" xmlns:service="urn:mace:shibboleth:2.0:services"
-    xmlns:profile="urn:mace:shibboleth:2.0:profile-handler" xmlns:relyingParty="urn:mace:shibboleth:2.0:relying-party"
+    xmlns:profile="urn:mace:shibboleth:2.0:idp:profile" xmlns:relyingParty="urn:mace:shibboleth:2.0:relying-party"
     xmlns:resolver="urn:mace:shibboleth:2.0:resolver" xmlns:afp="urn:mace:shibboleth:2.0:afp"
     xmlns:resource="urn:mace:shibboleth:2.0:resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="urn:mace:shibboleth:2.0:idp:services classpath:/schema/shibboleth-2.0-idp-service.xsd
                         urn:mace:shibboleth:2.0:services classpath:/schema/shibboleth-2.0-services.xsd
-                        urn:mace:shibboleth:2.0:profile-handler classpath:/schema/shibboleth-2.0-profile-handler.xsd
+                        urn:mace:shibboleth:2.0:idp:profile classpath:/schema/shibboleth-2.0-idp-profile.xsd
                         urn:mace:shibboleth:2.0:relying-party classpath:/schema/shibboleth-2.0-relying-party.xsd
                         urn:mace:shibboleth:2.0:resolver classpath:/schema/shibboleth-2.0-attribute-resolver.xsd
                         urn:mace:shibboleth:2.0:afp classpath:/schema/shibboleth-2.0-afp.xsd 
                         urn:mace:shibboleth:2.0:resource classpath:/schema/shibboleth-2.0-resource.xsd">
 
-<!--
-    <LoggingConfiguration>$IDP_HOME$/conf/logging.xml</LoggingConfiguration>
--->
-
-    <Service id="shibboleth.ProfileHandler"
-             xmlns="urn:mace:shibboleth:2.0:services"
-             xsi:type="profile:ShibbolethProfileHandlerManager">
-        <ConfigurationResource file="/data/conf1/protocol.xml" xsi:type="resource:ClasspathResource" />
-    </Service>
-
-    <Service id="shibboleth.RelyingPartyConfigurationManager"
-             xmlns="urn:mace:shibboleth:2.0:services"
-             xsi:type="relyingParty:SAMLMDRelyingPartyConfigurationManager">
-        <ConfigurationResource file="/data/conf1/relying-party.xml" xsi:type="resource:ClasspathResource" />
-    </Service>
-
     <Service id="shibboleth.AttributeResolver"
              xmlns="urn:mace:shibboleth:2.0:services"
              xsi:type="resolver:ShibbolethAttributeResolver">
         <ConfigurationResource file="/data/conf1/attribute-filter.xml" xsi:type="resource:ClasspathResource" />
     </Service>
 
+    <Service id="shibboleth.HandlerManager"
+             xmlns="urn:mace:shibboleth:2.0:services"
+             xsi:type="profile:IdPProfileHandlerManager">
+        <ConfigurationResource file="/data/conf1/handler.xml" xsi:type="resource:ClasspathResource" />
+    </Service>
+
+    <Service id="shibboleth.RelyingPartyConfigurationManager"
+             xmlns="urn:mace:shibboleth:2.0:services"
+             xsi:type="relyingParty:SAMLMDRelyingPartyConfigurationManager">
+        <ConfigurationResource file="/data/conf1/relying-party.xml" xsi:type="resource:ClasspathResource" />
+    </Service>
+
 </IdPConfig>
\ No newline at end of file
index 7361a8a..08b296a 100644 (file)
@@ -37,9 +37,9 @@ import org.springframework.mock.web.MockHttpServletResponse;
 import org.w3c.dom.Element;
 
 import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileHandlerManager;
 import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
 import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
-import edu.internet2.middleware.shibboleth.common.profile.provider.ShibbolethProfileHandlerManager;
 import edu.internet2.middleware.shibboleth.idp.profile.ShibbolethProfileRequest;
 import edu.internet2.middleware.shibboleth.idp.profile.ShibbolethProfileResponse;
 
@@ -59,8 +59,8 @@ public class SAML2AttributeQueryTestCase extends BaseConf1TestCase {
 
         MockHttpServletResponse servletResponse = new MockHttpServletResponse();
 
-        ShibbolethProfileHandlerManager handlerManager = (ShibbolethProfileHandlerManager) getApplicationContext()
-                .getBean("shibboleth.ProfileHandler");
+        ProfileHandlerManager handlerManager = (ProfileHandlerManager) getApplicationContext().getBean(
+                "shibboleth.HandlerManager");
         ProfileHandler handler = handlerManager.getProfileHandler(servletRequest);
         assertNotNull(handler);
 
@@ -73,7 +73,7 @@ public class SAML2AttributeQueryTestCase extends BaseConf1TestCase {
         assertTrue(response.contains(StatusCode.RESPONDER_URI));
         assertTrue(response.contains(StatusCode.REQUEST_DENIED_URI));
     }
-    
+
     /** Test a request where the Issuer is authenticated and has not requested any specific attributes. */
     public void testAuthenticatedIssuerNoProfileConfiguration() throws Exception {
         AttributeQuery query = buildAttributeQuery("urn:example.org:unitTest:sp1");
@@ -85,8 +85,8 @@ public class SAML2AttributeQueryTestCase extends BaseConf1TestCase {
 
         MockHttpServletResponse servletResponse = new MockHttpServletResponse();
 
-        ShibbolethProfileHandlerManager handlerManager = (ShibbolethProfileHandlerManager) getApplicationContext()
-                .getBean("shibboleth.ProfileHandler");
+        ProfileHandlerManager handlerManager = (ProfileHandlerManager) getApplicationContext().getBean(
+                "shibboleth.HandlerManager");
         ProfileHandler handler = handlerManager.getProfileHandler(servletRequest);
         assertNotNull(handler);
 
@@ -99,7 +99,7 @@ public class SAML2AttributeQueryTestCase extends BaseConf1TestCase {
         assertTrue(response.contains(StatusCode.RESPONDER_URI));
         assertTrue(response.contains(StatusCode.REQUEST_DENIED_URI));
     }
-    
+
     /** Test a request where the Issuer is authenticated and has not requested any specific attributes. */
     public void testAuthenticatedIssuerNoRequestAttributes() throws Exception {
         AttributeQuery query = buildAttributeQuery("urn:example.org:unitTestFed:sp2");
@@ -111,8 +111,8 @@ public class SAML2AttributeQueryTestCase extends BaseConf1TestCase {
 
         MockHttpServletResponse servletResponse = new MockHttpServletResponse();
 
-        ShibbolethProfileHandlerManager handlerManager = (ShibbolethProfileHandlerManager) getApplicationContext()
-                .getBean("shibboleth.ProfileHandler");
+        ProfileHandlerManager handlerManager = (ProfileHandlerManager) getApplicationContext().getBean(
+                "shibboleth.HandlerManager");
         ProfileHandler handler = handlerManager.getProfileHandler(servletRequest);
         assertNotNull(handler);
 
@@ -126,7 +126,7 @@ public class SAML2AttributeQueryTestCase extends BaseConf1TestCase {
         assertTrue(response.contains("Name=\"cn\""));
         assertTrue(response.contains("Name=\"uid\""));
     }
-    
+
     /**
      * Builds a basic attribute query.
      * 
diff --git a/tests/edu/internet2/middleware/shibboleth/idp/system/conf1/SAML2SSOTestCase.java b/tests/edu/internet2/middleware/shibboleth/idp/system/conf1/SAML2SSOTestCase.java
new file mode 100644 (file)
index 0000000..3aa92e0
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * 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 edu.internet2.middleware.shibboleth.idp.system.conf1;
+
+import java.io.StringWriter;
+
+import javax.servlet.http.HttpSession;
+
+import org.joda.time.DateTime;
+import org.opensaml.common.SAMLObjectBuilder;
+import org.opensaml.common.binding.encoding.MessageEncoder;
+import org.opensaml.common.binding.encoding.MessageEncoderFactory;
+import org.opensaml.saml2.binding.decoding.HTTPPostDecoder;
+import org.opensaml.saml2.core.AttributeQuery;
+import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.xml.io.Marshaller;
+import org.opensaml.xml.io.MarshallingException;
+import org.opensaml.xml.util.Base64;
+import org.opensaml.xml.util.XMLHelper;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.w3c.dom.Element;
+
+import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileHandlerManager;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+import edu.internet2.middleware.shibboleth.idp.authn.Saml2LoginContext;
+import edu.internet2.middleware.shibboleth.idp.profile.IdPProfileHandlerManager;
+import edu.internet2.middleware.shibboleth.idp.profile.ShibbolethProfileRequest;
+import edu.internet2.middleware.shibboleth.idp.profile.ShibbolethProfileResponse;
+
+/**
+ * 
+ */
+public class SAML2SSOTestCase extends BaseConf1TestCase {
+
+    /** Tests a request where the Issuer can not be authenticated. */
+    public void testUnathenticatedIssuer() throws Exception {
+        AuthnRequest authnRequest = buildAuthnRequest("urn:example.org:unitTest:sp1");
+        String authnRequestString = getSamlRequestString(authnRequest);
+
+        MockHttpServletRequest servletRequest = new MockHttpServletRequest();
+        servletRequest.setPathInfo("/IdP/saml2/SSONoAuth");
+        servletRequest.setParameter(HTTPPostDecoder.REQUEST_PARAM, Base64.encodeBytes(authnRequestString.getBytes()));
+
+        MockHttpServletResponse servletResponse = new MockHttpServletResponse();
+
+        ProfileHandlerManager handlerManager = (ProfileHandlerManager) getApplicationContext().getBean(
+                "shibboleth.HandlerManager");
+        ProfileHandler handler = handlerManager.getProfileHandler(servletRequest);
+        assertNotNull(handler);
+
+        // Process request
+        ProfileRequest profileRequest = new ShibbolethProfileRequest(servletRequest);
+        ProfileResponse profileResponse = new ShibbolethProfileResponse(servletResponse);
+
+        try {
+            handler.processRequest(profileRequest, profileResponse);
+            fail();
+        } catch (ProfileException e) {
+            // expected
+        }
+    }
+
+    public void testAuthenicatedIssuer() throws Exception {
+        AuthnRequest authnRequest = buildAuthnRequest("urn:example.org:unitTestFed:sp2");
+        String authnRequestString = getSamlRequestString(authnRequest);
+
+        MockHttpServletRequest servletRequest = new MockHttpServletRequest();
+        servletRequest.setPathInfo("/IdP/saml2/SSONoAuth");
+        servletRequest.setParameter(HTTPPostDecoder.REQUEST_PARAM, Base64.encodeBytes(authnRequestString.getBytes()));
+
+        MockHttpServletResponse servletResponse = new MockHttpServletResponse();
+
+        ProfileHandlerManager handlerManager = (ProfileHandlerManager) getApplicationContext().getBean(
+                "shibboleth.HandlerManager");
+        ProfileHandler handler = handlerManager.getProfileHandler(servletRequest);
+        assertNotNull(handler);
+
+        // Process request
+        ProfileRequest profileRequest = new ShibbolethProfileRequest(servletRequest);
+        ProfileResponse profileResponse = new ShibbolethProfileResponse(servletResponse);
+        handler.processRequest(profileRequest, profileResponse);
+
+        HttpSession session = servletRequest.getSession();
+        Saml2LoginContext loginContext = (Saml2LoginContext) session.getAttribute(Saml2LoginContext.LOGIN_CONTEXT_KEY);
+        assertNotNull(loginContext);
+    }
+
+    public void testSecondLeg() throws Exception {
+        AuthnRequest authnRequest = buildAuthnRequest("urn:example.org:unitTestFed:sp2");
+        
+        Saml2LoginContext loginContext = new Saml2LoginContext("urn:example.org:unitTestFed:sp2", authnRequest);
+        loginContext.setAuthenticationInstant(new DateTime());
+        loginContext.setAuthenticationMethod(IdPProfileHandlerManager.DEFAULT_AUTHEN_METHOD_URI);
+        loginContext.setPrincipalAuthenticated(true);
+        loginContext.setPrincipalName("testUser");        
+
+        MockHttpServletRequest servletRequest = new MockHttpServletRequest();
+        servletRequest.setPathInfo("/IdP/saml2/SSONoAuth");
+        
+        HttpSession session = servletRequest.getSession();
+        session.setAttribute(Saml2LoginContext.LOGIN_CONTEXT_KEY, loginContext);
+
+        MockHttpServletResponse servletResponse = new MockHttpServletResponse();
+
+        ProfileHandlerManager handlerManager = (ProfileHandlerManager) getApplicationContext().getBean(
+                "shibboleth.HandlerManager");
+        ProfileHandler handler = handlerManager.getProfileHandler(servletRequest);
+        assertNotNull(handler);
+
+        // Process request
+        ProfileRequest profileRequest = new ShibbolethProfileRequest(servletRequest);
+        ProfileResponse profileResponse = new ShibbolethProfileResponse(servletResponse);
+        handler.processRequest(profileRequest, profileResponse);
+
+    }
+
+    protected AuthnRequest buildAuthnRequest(String requester) {
+        SAMLObjectBuilder<Issuer> issuerBuilder = (SAMLObjectBuilder<Issuer>) builderFactory
+                .getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
+        Issuer issuer = issuerBuilder.buildObject();
+        issuer.setValue(requester);
+
+        SAMLObjectBuilder<AuthnRequest> authnRequestBuilder = (SAMLObjectBuilder<AuthnRequest>) builderFactory
+                .getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME);
+        AuthnRequest request = authnRequestBuilder.buildObject();
+        request.setID("1");
+        request.setIssueInstant(new DateTime());
+        request.setIssuer(issuer);
+
+        return request;
+    }
+
+    protected String getSamlRequestString(AuthnRequest request) throws MarshallingException {
+        Marshaller marshaller = marshallerFactory.getMarshaller(request);
+        Element requestElem = marshaller.marshall(request);
+        String requestString = XMLHelper.nodeToString(requestElem);
+        return Base64.encodeBytes(requestString.getBytes());
+    }
+}
\ No newline at end of file