4 Replies Latest reply on Jan 18, 2012 7:53 AM by pcraveiro

    Externalize IDP and SP Configurations

    pcraveiro

      Hi,

       

          I'm deploying Picketlink in a developent/test/production environment and I'm trying to find the best solution to manage the IDPs and SPs configurations, basically the ones in picketlink-idfed.xml. The best solution by far would be a Web Application to managed this configurations (maybe creating a new SAMLConfigurationProvider implementadion), but I have no time for this now.

       

          The SP Valve (both Post and Redirect) provide a attribute named configFile. This one suits my needs since I want to remove the picketlink-idfed.xml from inside the SPs. The problem is that this file is always obtained by the Valve from inside the SP's WAR file. Is there a way to force the Valve to get this file from another location, outside de SP's WAR file ?

       

          Another question, it's possible to use the same attribute in the IDP ? It seems that the IDPWebBrowserValve does not support this ...

       

      Best regards,

      Pedro Igor

        • 1. Re: Externalize IDP and SP Configurations
          firstlion

          Hi,

          The following works fine for me: In the standalone.xml - configFile add the following under system-properties:

           

          <property name="idp.url" value="http://localhost:8080/idp/"/>

          <property name="zponf.url" value="http://localhost:8080/zponf/priv/anmelden.jsf"/>

          <property name="trusted.domain" value="localhost"/>

           

          Of course, you have to edit it for your needs. In IDP-picketlink-idfed.xml:

          <PicketLinkIDP xmlns="urn:picketlink:identity-federation:config:1.0" >

          <IdentityURL>${idp.url::http://localhost:8080/idp/}</IdentityURL>

          <Trust>

             <Domains>${trusted.domain::localhost}</Domains>

          </Trust>

          </PicketLinkIDP>

           

          And in SP-picketlink-idfed.xml:

          <PicketLinkSP xmlns="urn:picketlink:identity-federation:config:1.0" ServerEnvironment="jboss">

          <IdentityURL>${idp.url::http://localhost:8080/idp/}</IdentityURL>

          <ServiceURL>${zponf.url::http://localhost:8080/zponf/priv/anmelden.jsf}</ServiceURL>

          </PicketLinkSP>

           

          So, the idfed.xml-files aren't used anymore (there are online the default-values defined). The real values to use, you can define and edit in the standalone.xml-file. If you don't use the standalone-mode of JBoss or you use another server, there is a similar way, i think.

           

          I hope, it helps you,

           

          Martin

          • 2. Re: Externalize IDP and SP Configurations
            pcraveiro

            Hi Martin,

             

                Thanks for your reply.

             

                Actually I'm already using system properties for some configurations. But in my case, I also using signatures. When using signatures the configurations related with the KeyProvider are hard to externalize using system properties. Here is a example of my picketlink-idfed.xml file:

             

            <PicketLinkSP xmlns="urn:picketlink:identity-federation:config:1.0">

                <IdentityURL>${idp-sig.url::http://localhost:8080/idp/}</IdentityURL>

                <ServiceURL>http://${jboss.bind.address}:8080/sp-example/</ServiceURL>

                <KeyProvider

                    ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager">

                    <Auth Key="KeyStoreURL" Value="${jboss.server.home.dir}/customer_deploy/configurations/jbid_test_keystore.jks" />

                    <Auth Key="KeyStorePass" Value="###### />

                    <Auth Key="SigningKeyPass" Value="###### />

                    <Auth Key="SigningKeyAlias" Value="${jboss.bind.address}" />

                    <ValidatingAlias Key="192.168.1.1" Value="192.168.1.1" />

                    <ValidatingAlias Key="192.168.1.2" Value="192.168.1.2" />

                    ...

                </KeyProvider>

             

            </PicketLinkSP>

             

                I think it's a good and common feature to allow read this file from any directory in the filesystem. That way, SPs and IDPs don't need to worry about enviroment (dev, prod, test) differences.

             

                To workaround this I'm working in a custom implementation of SAMLConfigurationProvider.

             

            Best regards,

            Pedro Igor

            • 3. Re: Externalize IDP and SP Configurations
              pcraveiro

              Hi,

               

                  Here is a Custom SAMLConfigurationProvider  that allows to externalize and also to avoid some SP configurations duplication using a picketlink-idfed.xml file as template.

               

               

              public class ExternalSAMLConfigurationProvider implements SAMLConfigurationProvider

              {

               

                 private static final String DEFAULT_IDP_CONFIG_FILE = System.getProperty("jboss.server.home.dir") + "/picketlink/picketlink-idfed-idp.xml";

                 private static final String DEFAULT_CONFIG_PROTOCOL = "file://";

               

                 /* (non-Javadoc)

                  * @see org.picketlink.identity.federation.web.util.SAMLConfigurationProvider#getIDPConfiguration()

                  */

                 @Override

                 public IDPType getIDPConfiguration() throws ProcessingException

                 {

                    try

                    {

                       return ConfigurationUtil.getIDPConfiguration(getConfiguration(getIDPConfigurationFilePath()));

                    }

                    catch (Exception e)

                    {

                       throw new ProcessingException("Could not load IDP configuration: " + getIDPConfigurationFilePath(), e);

                    }

                 }

               

                 /* (non-Javadoc)

                  * @see org.picketlink.identity.federation.web.util.SAMLConfigurationProvider#getSPConfiguration()

                  */

                 @Override

                 public SPType getSPConfiguration() throws ProcessingException

                 {

                    String serviceProviderId = loadServiceProviderId();

               

                    try

                    {

                       SPType spConfiguration = ConfigurationUtil.getSPConfiguration(getConfiguration(getSPConfigurationFilePath(serviceProviderId)));

               

                   // the keyprovider configuration is overrided by the ones defined in the template file

                       spConfiguration.setKeyProvider(getSPTemplateConfig().getKeyProvider());

               

                       return spConfiguration;

                    }

                    catch (Exception e)

                    {

                       throw new ProcessingException("Could not load SP configuration: " + getIDPConfigurationFilePath(), e);

                    }

                 }

               

                 /**

                 * Loads a picketlink-idfed.xml file to be used as a template for the SP configuration. This avoid to duplicate some configurations like the ones related with the KeyProvider.

                 */

                 private SPType getSPTemplateConfig() throws ParsingException, FileNotFoundException

                 {

                    return ConfigurationUtil.getSPConfiguration(new FileInputStream(System.getProperty("jboss.server.home.dir") + "/picketlink/picketlink-idfed-keyprovider-config.xml"));

                 }

               

                 /**

                 * Loads a identifier to be used to locate the specific picketlink-idfed.xml file for a SP.

                 */  

                 private String loadServiceProviderId()

                 {

                    Properties serviceProviderProperties = new Properties();

               

                    try

                    {

                       serviceProviderProperties.load(Thread.currentThread().getContextClassLoader()

                             .getResourceAsStream("picketlink.properties"));

               

                       return serviceProviderProperties.getProperty("picketlink.sso.sp.id");

                    }

                    catch (Exception e)

                    {

                       throw new IllegalStateException("Nao foi possivel ler o arquivo de propriedades do Picketlink.", e);

                    }

                    finally

                    {

                       serviceProviderProperties = null;

                    }

                 }

               

                 /**

                 * Returns the SP configuration file path.

                 */  

                 private String getSPConfigurationFilePath(String serviceProviderId)

                 {

                    String spConfigDir = System.getProperty("picketlink.config.sp.file.dir", System.getProperty("jboss.server.home.dir") + "/picketlink");

               

                    return DEFAULT_CONFIG_PROTOCOL + spConfigDir + "/picketlink-idfed-" + serviceProviderId + ".xml";

                 }

               

                 /**

                 * Returns the IDP configuration file path.

                 */  

                 private String getIDPConfigurationFilePath()

                 {

                    return DEFAULT_CONFIG_PROTOCOL + System.getProperty("picketlink.config.idp.file", DEFAULT_IDP_CONFIG_FILE);

                 }

               

                 /**

                 * Loads a file

                 */  

                 protected InputStream getConfiguration(String fileName) throws ConfigurationException

                 {

                    URL configurationFileURL = null;

               

                    try

                    {

                       if (configurationFileURL == null)

                       {

                          configurationFileURL = Thread.currentThread().getContextClassLoader().getResource(fileName);

                       }

               

                       if (configurationFileURL == null)

                       {

                          configurationFileURL = new URL(fileName);

                       }

               

                       return configurationFileURL.openStream();

                    }

                    catch (Exception e)

                    {

                       throw new ConfigurationException("The file could not be loaded: " + fileName, e);

                    }

                 }

              }

              • 4. Re: Externalize IDP and SP Configurations
                pcraveiro

                Hi,

                 

                    After using my custom configProvider I realized that Picketlink first checks the existence for a picketlink-idfed.xml file inside the application, by default in WEB-INF/picketlink-idfed.xml. Here is a snippet from the BaseFormAuthenticator class:

                 

                protected void processConfiguration()

                   {

                     ServletContext servletContext = context.getServletContext();

                      InputStream is = servletContext.getResourceAsStream(configFile);

                      if (is == null)

                         throw new RuntimeException(ErrorCodes.SERVICE_PROVIDER_CONF_FILE_MISSING + configFile);

                      try

                      {

                         if (configProvider != null)

                         {

                            spConfiguration = configProvider.getSPConfiguration();

                         }

                         else

                         {

                            spConfiguration = ConfigurationUtil.getSPConfiguration(is);

                         }

                 

                         if (StringUtil.isNotNull(spConfiguration.getIdpMetadataFile()))

                         {

                            processIDPMetadataFile(spConfiguration.getIdpMetadataFile());

                         }

                         else

                         {

                            this.identityURL = spConfiguration.getIdentityURL();

                         }

                         this.serviceURL = spConfiguration.getServiceURL();

                         this.canonicalizationMethod = spConfiguration.getCanonicalizationMethod();

                 

                         log.info("BaseFormAuthenticator:: Setting the CanonicalizationMethod on XMLSignatureUtil::"

                               + canonicalizationMethod);

                         XMLSignatureUtil.setCanonicalizationMethodType(canonicalizationMethod);

                 

                         if (trace)

                            log.trace("Identity Provider URL=" + this.identityURL);

                      }

                      catch (Exception e)

                      {

                         throw new RuntimeException(e);

                      }

                   }

                 

                The motivation behind my custom configProvider is to remove the picketlink-idfed.xml from the applications and if this file is not present in the default location a exception is throwed

                 

                I think the right thing to do here is to throw the exception only when no custom configProvider  is specified. Something like this:

                 

                protected void processConfiguration()

                   {

                      try

                      {

                         if (configProvider != null)

                         {

                            spConfiguration = configProvider.getSPConfiguration();

                         }

                         else

                         {

                            ServletContext servletContext = context.getServletContext();

                            InputStream is = servletContext.getResourceAsStream(configFile);

                           

                            if (is == null)

                                 throw new RuntimeException(ErrorCodes.SERVICE_PROVIDER_CONF_FILE_MISSING + configFile);

                           

                            spConfiguration = ConfigurationUtil.getSPConfiguration(is);

                         }

                 

                ...

                }

                 

                What do you think ?

                 

                Thanks,

                Pedro Igor