Pac4j spring-security with SAML and Okta as IDP

543 views
Skip to first unread message

ivan morozov

unread,
Feb 16, 2016, 4:56:27 AM2/16/16
to pac4j-users
Hi @ all,

first, thank you for developing a great library!

Currently im trying to integrate Pac4j in Spring Application and using Okta as IDP.

My configuration is pretty similar to the demo application :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
          http://www.springframework.org/schema/security
          http://www.springframework.org/schema/security/spring-security-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   
<bean class="de.kredito.WebConfiguration"/>
   
<context:annotation-config/>

   
<security:authentication-manager alias="authenticationManager">
       
<security:authentication-provider ref="clientProvider" />
   
</security:authentication-manager>

    <security:http pattern="/rest/**" entry-point-ref="samlEntryPoint">
       
<security:headers disabled="true" />
       
<security:intercept-url pattern="/rest/**" access="isAuthenticated()" />
       
<security:csrf disabled="true"/>
   
</security:http>

    <bean id="samlEntryPoint" class="org.pac4j.springframework.security.web.ClientAuthenticationEntryPoint">
       
<property name="client" ref="samlClient" />
   
</bean>

   
<bean id="samlConfig" class="org.pac4j.saml.client.SAML2ClientConfiguration">
       
<property name="keystorePath" value="resource:security/samlKeystore.jks" />
       
<property name="keystorePassword" value="pac4j-demo-passwd" />
       
<property name="privateKeyPassword" value="pac4j-demo-passwd" />
       
<property name="identityProviderMetadataPath" value="resource:metadata/okta.xml" />
       
<property name="maximumAuthenticationLifetime" value="3600" />
       
<property name="serviceProviderEntityId" value="http://localhost:8080/callback?client_name=SAML2Client" />
       
<property name="serviceProviderMetadataPath" value="sp-metadata.xml" />
   
</bean>

   
<bean id="samlClient" class="org.pac4j.saml.client.SAML2Client">
       
<constructor-arg name="configuration" ref="samlConfig" />
   
</bean>

   
<bean id="clients" class="org.pac4j.core.client.Clients">
       
<property name="callbackUrl" value="http://localhost:8080/rest/login" />
       
<property name="clients">
           
<list>
               
<ref bean="samlClient" />
           
</list>
       
</property>
   
</bean>
    <bean id="clientFilter" class="org.pac4j.springframework.security.web.ClientAuthenticationFilter">
       
<property name="clients" ref="clients" />
       
<property name="sessionAuthenticationStrategy" ref="sas" />
       
<property name="authenticationManager" ref="authenticationManager" />
   
</bean>
   
<bean id="clientProvider" class="org.pac4j.springframework.security.authentication.ClientAuthenticationProvider">
       
<property name="clients" ref="clients" />
   
</bean>
   
<bean id="httpSessionRequestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache" />
   
<bean id="sas" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />
</beans>

The Okta configuration require at least two params:
  1. Single sign on URL
SP Entity ID is : http://localhost:8080/callback?client_name=SAML2Client

But what should be the SSO Url? 

Another question is, is that right, that my callback uri is the place where i should get the ClientAuthenticationToken and go on with the user authorisation?


Thank you guys in advance!
Ivan



    Jérôme LELEU

    unread,
    Feb 16, 2016, 5:28:51 AM2/16/16
    to ivan morozov, pac4j-users
    Hi,

    The SSO url is the same as the SP entity ID. At least, this is the configuration of the demo.

    The callback url is the place where the authentication process is finished: SAML credentials returned by the IdP are processed, interactions happen with the IdP and finally a user profile is created and stored as a ClientAuthenticationToken to fit in the Spring security model.

    Roles / permissions can be computed using an AuthorizationGenerator attached to the SAML2Client.

    Thanks.
    Best regards,
    Jérôme




    --
    You received this message because you are subscribed to the Google Groups "pac4j-users" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-users...@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

    ivan morozov

    unread,
    Feb 16, 2016, 7:00:23 AM2/16/16
    to pac4j-users, moroz...@gmail.com
    Hey Jerome,

    thank you for the quick answer!

    By leaving the configuration like this (SSO and SP entity ID on: http://localhost:8080/callback?client_name=SAML2Client) my configuration show the behavior as follow:

    1. Im starting SP initiated flow by calling localhost:8080/rest
    2. Application redirect me to Okta
    3. After authenticating in Okta my browser points me to http://localhost:8080/callback?client_name=SAML2Client and sending the SAMLResponse in Form Data of the request and also this: 
    Name
    Path

    It looks like for me that My application trying to redirect me to admin/auth like the definition in security-config.xml (<property name="callbackUrl" value="http://localhost:8080/admin/auth.html" />)
    But why it adds the client name as query parameter and where the authorisation happened?

    I have a break point in :
    <bean id="clientProvider" class="org.pac4j.springframework.security.authentication.ClientAuthenticationProvider">
    <property name="clients" ref="clients" />
    </bean>

    In the ClientAuthenticationFilter class authenticate method. But it look like that my flow never reach this authorisation point.
    ...

    Jérôme LELEU

    unread,
    Feb 16, 2016, 8:22:25 AM2/16/16
    to ivan morozov, pac4j-users
    Hi,

    OK. I missed it in your previous post, but there is an issue with the callback url.

    The callback url is the url where the IdP will redirect the user after a successful authentication (it should be http://localhost:8080/callback). To reach an url, you should always call it directly and let Spring Security saves and restores it.
    The regular flow: myapp/protected.html -> theidp/login -> myapp/callback -> myapp/protected.html

    There is a specific client_name parameter on the callback url to be able to distinguish between multiple authentication processes (as there is only one callback url; in fact, you may have several callback urls, but I don't recommend it).
    so it means on the IdP side, you must define for the SSO url the callback url of the app + the client_name parameter. Thus, http://localhost:8080/callback?client_name=SAML2Client

    Thanks.
    Best regards,
    Jérôme




    --

    ivan morozov

    unread,
    Feb 16, 2016, 10:25:12 AM2/16/16
    to pac4j-users, moroz...@gmail.com
    Hi,

    i have in my app:
    <bean id="clients" class="org.pac4j.core.client.Clients">

       
    <property name="callbackUrl" value="http://localhost:8080/callback" />

       
    <property name="clients">
           
    <list>
               
    <ref bean="samlClient" />
           
    </list>
       
    </property>
    </bean>
    <bean id="samlConfig" class="org.pac4j.saml.client.SAML2ClientConfiguration">
       
    <property name="keystorePath" value="resource:security/samlKeystore.jks" />
       
    <property name="keystorePassword" value="pac4j-demo-passwd" />
       
    <property name="privateKeyPassword" value="pac4j-demo-passwd" />
       
    <property name="identityProviderMetadataPath" value="resource:metadata/okta.xml" />
       
    <property name="maximumAuthenticationLifetime" value="3600" />
       
    <property name="serviceProviderEntityId" value="http://localhost:8080/callback?client_name=SAML2Client" />
       
    <property name="serviceProviderMetadataPath" value="sp-metadata.xml" />
    </bean>
    And in Okta 
    SSO URL : http://localhost:8080/callback?client_name=SAML2Client
    SP identity URL : http://localhost:8080/callback?client_name=SAML2Client

    Anyway,  this does not work for me. After authentication in Okta, im redirected to sending POST with assertion XML to  http://localhost:8080/callback?client_name=SAML2Client which is resulting on 404 HTTP.
    What can i do to handle the assertion in this case and where is the entry point to get ClientAuthenticationToken, can you please help me with an example? Thank you
    Ivan

    ...

    ivan morozov

    unread,
    Feb 16, 2016, 4:12:20 PM2/16/16
    to pac4j-users, moroz...@gmail.com
    This is actually a pretty interesting case that i have, so if im trying the demo everything works, the same do not work in my application.
    • Im using the same versions of spring-security, pac4j etc...
    • the configuration only differ only in the name of http pattern 
      <security:http pattern="/admin/auth.html/**" entry-point-ref="samlEntryPoint">

    •    
      <security:headers disabled="true" />

    •    
      <security:intercept-url pattern="/admin/auth.html/**" access="isAuthenticated()" />
      </security:http>

    • the other configuration is the same, in my app i removed all clients except saml
    • The Okta (IDP) metadata is the same in both cases
    The example works completely fine, im starting the authorisation, typing my credentials to okta and see the credentials page.

    Trying the same in my prod application, everything is fine till the authentication in my app. After typing the credentials in Okta im lading on http://localhost:8080/callback?client_name=SAML2Client - which yields 404 Error!
    Moreover, after looking at the "last" redirect in browser (http://localhost:8080/callback?client_name=SAML2Client) i see that the client (browser) trying to POST the SAML Assertion XML to this Link, but for any reason my app do not start authentication!

    I tried to debug the behavior in the demo application and noticed that ClientAuthenticationProvider$authenticate is triggered, for any reason i never reach this point in my prod application. I have not idea why this happen how its happen... If somebody have an idea, it would be really appreciated!!

    P.S 
    My prod application is a large, incrementally grown Spring application.

    Much thanks in advance
    Ivan

    Jérôme LELEU

    unread,
    Feb 17, 2016, 4:19:27 AM2/17/16
    to ivan morozov, pac4j-users
    Hi,

    The callback url in client or clients is just a definition. The component which actually receives the callbacks from the identity providers is the ClientAuthenticationFilter : are you sure it's defined?

    It would completely explain the 404 you get.

    Thanks.
    Best regards,
    Jérôme


    --

    Jérôme LELEU

    unread,
    Feb 17, 2016, 4:21:37 AM2/17/16
    to ivan morozov, pac4j-users
    Hi,

    As I said in a previous post, do you have the ClientAuthenticationFilter properly configured?

    Thanks.
    Best regards,
    Jérôme


    ivan morozov

    unread,
    Feb 17, 2016, 8:14:03 AM2/17/16
    to pac4j-users, moroz...@gmail.com
    Hey Jerome, 
    Yes, it is defined, the same way as in demo app. 
    <!-- common to all clients -->
    <bean id="clientFilter" class="org.pac4j.springframework.security.web.ClientAuthenticationFilter">

       
    <property name="clients" ref="clients" />

       
    <property name="sessionAuthenticationStrategy" ref="sas" />
       
    <property name="authenticationManager" ref="authenticationManager" />
    </bean>

    its referring clients defined as 
    <bean id="clients" class="org.pac4j.core.client.Clients">
       
    <property name="callbackUrl" value="http://localhost:8080/callback" />
       
    <property name="clients">
           
    <list>
               
    <ref bean="samlClient" />
           
    </list>
       
    </property>
    </bean>


    ivan morozov

    unread,
    Feb 17, 2016, 9:39:59 AM2/17/16
    to pac4j-users, moroz...@gmail.com
    I finally figured it out, thanks again Jerome to push me in the right direction.

    The problem was that my clientFilter was configured but not used, because i removed everything from the demo configuration except the SAML client configuration. 
    However the demo configuration had also this piece of configuration 
    <security:http pattern="/**" entry-point-ref="casEntryPoint">

           
    <security:csrf disabled="true"/>
    <security:headers disabled="true" />

           
    <<security:custom-filter after="CAS_FILTER" ref="clientFilter" />
           
    <security:intercept-url pattern="/cas/restricted.jsp" access="hasRole('ADMIN')" />
           
    <security:intercept-url pattern="/cas/**" access="isAuthenticated()" />
           
    <security:intercept-url pattern="/**" access="permitAll()" />
           
    <security:logout logout-success-url="/" />
       
    </security:http>

    which looked for me like only for the CAS client so i removed it.
    Anyway the important part was the application of the clientFilter on the http pattern.
    After adding it into my security configuration the authorisation process succeed.  

    Cheers
    Ivan

    Jérôme LELEU

    unread,
    Feb 17, 2016, 9:43:54 AM2/17/16
    to ivan morozov, pac4j-users
    Glad to hear it!
    Reply all
    Reply to author
    Forward
    0 new messages