CAS Service parameter?

952 views
Skip to first unread message

Andy Warner

unread,
Jan 18, 2016, 7:59:48 AM1/18/16
to pac4j...@googlegroups.com
Folks,

I build a CAS version that uses pac4j-saml.  I can login thru the CAS, getting redirected to a Shibboleth IdP, authenticate with an ldap connection and get redirected back to CAS after successful login, but I can’t get it to follow the service parameter like CAS would normally do.  I have a Python app that uses CAS for auth by just redirecting to CAS when there is not a ticket param and uses serviceValidate to verify the ticket when it has one, so works great for CAS without SAML, just a MySQL connection.  Authenticating thru pac4j-saml, the TGT and ST gets set, but I can’t get it to redirect to the service parameter.  If I could get that working, then the python app could just call the serviceValidate URI on CAS to validate the ticket and life would be good,

For example:

https://auth.test.com:8443/cas/login?client_name=SAML2Client&needs_client_redirection=true&service=https://app.test.net/login?fact=19

Normally after authentication the user gets redirected to app.test.net/login?fact=19 

Any ideas of what I’m doing wrong would be great.  Seems that pac4j-saml cause CAS to ignore the service parameter.

Thanks
Andy

Jérôme LELEU

unread,
Jan 18, 2016, 8:57:55 AM1/18/16
to Andy Warner, pac4j-users
Hi,

With the url you provide, no login page is displayed, isn't it?

Can you call the same url without the client_name and needs_client_redirection parameters, and then click on the SAML IdP link you added in your login page using ${SAML2ClientUrl}?

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.

Andy 👍

unread,
Jan 18, 2016, 10:50:12 AM1/18/16
to Jérôme LELEU, pac4j-users
Jérôme,

I does redirect to the IdP, I thought because of the setting in applicationContext.xml, right ?


    <bean id="samlConfig" class="org.pac4j.saml.client.SAML2ClientConfiguration"
          c:keystorePassword="pac4j-demo-passwd"
          c:privateKeyPassword="pac4j-demo-passwd"
          c:keystorePath="resource:samlKeystore.jks"
          c:identityProviderMetadataPath="resource:idp-metadata.xml"
          c:identityProviderEntityId="https://idp.test.com:8443/idp/shibboleth"
          c:serviceProviderEntityId="urn:mace:saml:pac4j.org"/>

    <bean id="saml1" class="org.pac4j.saml.client.SAML2Client"
          c:configuration-ref="samlConfig" />

    <bean id="clients" class="org.pac4j.core.client.Clients">
        <property name="callbackUrl" value="http://localhost:8080/cas/login" />
        <property name="clients">
            <list>
                <ref bean="saml1" />
            </list>
        </property>
    </bean>

But after I auth, instead of being redirected to the service params URLs, I jsut get sent back to the CAS

Thanks
Andy

Andy 👍

unread,
Jan 18, 2016, 10:52:54 AM1/18/16
to Jérôme LELEU, pac4j-users
Actually, when I changed the callbackUrl below, then the CAS TGT ans ST operations fail.
Seems like there needs to be an additional redirectionUrl to get me to the app after login completes ?

Thanks
Andy

Andy 👍

unread,
Jan 18, 2016, 10:55:34 AM1/18/16
to pac4j...@googlegroups.com
oh, the auth.test is just an example, it's not accessible to the internet

Jérôme LELEU

unread,
Jan 18, 2016, 10:59:09 AM1/18/16
to Andy 👍, pac4j-users
Hi,

The /login url acts both as a redirector to the IdP and both as a gateway for the login page by computing the redirection urls and saving the service in session.

So you must display the login page to be sure the service has been saved in session before clicking on a link to redirect to the identity provider.

Last time I tested it, it worked perfectly. Which CAS server version do you use?

Thanks.
Best regards,
Jérôme

Andy 👍

unread,
Jan 18, 2016, 12:31:01 PM1/18/16
to Jérôme LELEU, pac4j-users
Jérôme,

I'm using these versions:
        <cas.version>4.1.3</cas.version>
        <pac4j.version>1.7.1</pac4j.version>

The redirect to the IdP works, but appears to work based on the URLs in the metadata.xml file.  In my case, it appears that the callbackUrl given in the authenticationContext.xml file must point to the cas service login URL and the service parameter gets ignored and not carried forward in the redirects, so after the login completes the user gets redirected to CAS and not the the service param url.

Thanks
Andy

Jérôme LELEU

unread,
Jan 18, 2016, 1:51:37 PM1/18/16
to Andy 👍, pac4j-users
Hi,

The redirection to the Idp works based on the SAML configuration (identityProviderEntityId) while the redirection back to the CAS server is based on the callbackUrl (and IdP configuration).


Can you turn on DEBUG logs on org.jasig.cas.support.pac4j?

Thanks.
Best regards,
Jérôme

Andy 👍

unread,
Jan 18, 2016, 4:38:52 PM1/18/16
to Jérôme LELEU, pac4j-users
Jérôme,

So, just in my dev environment, I'm hitting this URL (https://localhost:8443/hardchalk/login?client_name=SAML2Client&needs_client_redirection=true&service=http://localhost:8090/login?fact=19) which I though would redirect me to the application after auth is completed following the service param, the app being at http://localhost:8090/login?fact=19 which would see the ST, then it would call serviceValidate on it and allow access, just like it does with regular CAS,   but instead it just redirects me to https://localhost:8443/hardchalk/login?client_name=SAML2Client which is basically the CAS LogIn Successful page.

I turned on debug for org.jasig.cas.support.pac4j and it just shows null for the save service

2016-01-18 12:53:44,995 INFO [org.jasig.cas.services.DefaultServicesManagerImpl] - <Reloading registered services.>
2016-01-18 12:53:44,998 INFO [org.jasig.cas.services.DefaultServicesManagerImpl] - <Loaded 2 services.>
2016-01-18 12:55:31,457 DEBUG [org.jasig.cas.support.pac4j.web.flow.ClientAction] - <clientName: null>
2016-01-18 12:55:31,457 DEBUG [org.jasig.cas.support.pac4j.web.flow.ClientAction] - <save service: null>
2016-01-18 12:55:31,457 DEBUG [org.jasig.cas.support.pac4j.web.flow.ClientAction] - <SAML2ClientUrl -> https://localhost:8443/hardchalk/login?client_name=SAML2Client&needs_client_redirection=true>
2016-01-18 12:55:44,994 INFO [org.jasig.cas.services.DefaultServicesManagerImpl] - <Reloading registered services.>
2016-01-18 12:55:44,996 INFO [org.jasig.cas.services.DefaultServicesManagerImpl] - <Loaded 2 services.>
2016-01-18 12:56:06,504 DEBUG [org.jasig.cas.support.pac4j.web.flow.ClientAction] - <clientName: SAML2Client>
2016-01-18 12:56:06,504 DEBUG [org.jasig.cas.support.pac4j.web.flow.ClientAction] - <client: <SAML2Client> | callbackUrl: https://localhost:8443/hardchalk/login?client_name=SAML2Client | name: null | isDirectRedirection: false | enableContextualRedirects: false |>
2016-01-18 12:56:06,504 DEBUG [org.pac4j.saml.context.SAML2ContextProvider] - <Creating message storage by org.pac4j.saml.storage.EmptyStorageFactory>
2016-01-18 12:56:06,749 DEBUG [org.jasig.cas.support.pac4j.web.flow.ClientAction] - <requires http action: {}
<RequiresHttpAction> | code: 200 |
        at org.pac4j.core.exception.RequiresHttpAction.ok(RequiresHttpAction.java:75)
        at org.pac4j.core.client.BaseClient.getCredentials(BaseClient.java:215)

Thanks for all the help on this.
Andy

Jérôme LELEU

unread,
Jan 19, 2016, 7:57:06 AM1/19/16
to Andy 👍, pac4j-users
Hi,

No, you need to call the login page before to save the service. The automatic redirection does not save (and thus does not restore) the given service.

I will certainly improve that in a future version.

Thanks.
Best regards,
Jérôme

Andy 👍

unread,
Jan 19, 2016, 8:27:47 AM1/19/16
to pac4j...@googlegroups.com
Jérôme,

Sorry, I'm confused, I think I am calling the cas login page:

https://localhost:8443/hardchalk/login?client_name=SAML2Client&needs_client_redirection=true&service=http://localhost:8090/login?fact=19

I just renamed cas to hardchalk so it would not step on another cas instance in tomcat.

From the pom:

    <modelVersion>4.0.0</modelVersion>
    <artifactId>hardchalk</artifactId>
    <groupId>com.hardchalk</groupId>
    <version>1.0</version>
    <packaging>war</packaging>
    <name>CAS Pac4J Client</name>
    <description>CAS Pac4J Client</description>

So, it's still just hitting the cas login page, which immediately redirects to the IdP login page and apparentlyt is not saving the service param.
It appears to me that the  c:identityProviderMetadataPath="resource:idp-metadata.xml" file defined in applicationContext.xml has this line:
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.wolflake.com:8443/idp/profile/SAML2/POST/SSO"/>
Which causes the redirect to the IdP for auth like this:

https://idp.wolflake.com:8443/idp/profile/SAML2/POST/SSO;jsessionid=7D7F72C5BE45B994191A590DF55AF411?execution=e1s1

The calbackUrl in applicationContext.xml appears to require pointing at the cas login page:

 <property name="callbackUrl" value="https://localhost:8443/hardchalk/login" />

I assumed that this is to get the TGT and the ST, because if I change that to the app URL it fails to get the tickets from CAS with an  IdP error.

It seems that the service param in the URL does not get saved or somehow gets lost between redirects.  If I get time, I'll debug this to find out why the service is not getting passed thru after the IdP auth.

Thanks
Andy

Jaroslav Kačer

unread,
Jan 19, 2016, 11:18:14 AM1/19/16
to pac4j-users
Hi Andy!

I remember I had a similar discussion with Jerome here a long time ago, unfortunately I'm not able to find it here anymore.

However, I can tell you what I did: I modified the ClientAction class in CAS module cas-server-support-pac4j. In the doExecute() method, I have:
// Let's read the desired service here and store it to the session.
// If the client accesses the SAML login directly - not via the main login page - we must save the service into the session
// to be able to restore it after the login completes.
final String serviceIdFromClient = request.getParameter(SERVICE);
logger
.debug("ServiceID: {}", serviceIdFromClient);
       
if (StringUtils.isNotBlank(serviceIdFromClient)) {
   
final Service serviceFromFlow = (Service) context.getFlowScope().get(SERVICE);
   
if (serviceFromFlow != null) {
      session
.setAttribute(SERVICE, serviceFromFlow);
   
} else {
      logger
.warn("No service found for Service ID {} in the web flow. After successful authentication, the user"
                 
+ " will not get forwarded to the application and no ST will be created. Referer: {}",
                  serviceIdFromClient
, request.getHeader("Referer"));
   
}
} else {
   logger
.warn("No service provided. This is only a problem if comming from the application, not from IdP."
               
+ " After successful authentication, the user will not get forwarded to the application and no ST will be created."
               
+ " Referer: {}", request.getHeader("Referer"));

   
// If RelayState is specified and this is an IdP-initiated request, let's use the value of RelayState.
   
final boolean thisIsFirstPass = !(Boolean.TRUE.equals(expectingIdpResponse));
   
if (StringUtils.isNotBlank(relayState) && thisIsFirstPass) {
      logger
.info("Probably IdP-initiated authentication. Empty service and non-empty relay state --> Relay state will become service for this login.");
       
final Service fakeServiceForRelay = new SimpleWebApplicationServiceImpl(relayState);
       session
.setAttribute(SERVICE, fakeServiceForRelay);
       context
.getFlowScope().put(SERVICE, fakeServiceForRelay);
   
}
 
}


at the beginning after reading client name etc. And then, almost at the end, there is
            // retrieve parameters from web session
           
final Service service = (Service) session.getAttribute(SERVICE);
            context
.getFlowScope().put(SERVICE, service);
           
if (service != null) {
                request
.setAttribute(SERVICE, service.getId());
           
} else {
                logger
.warn("No service could be restored from user session!");
           
}


Some of this code is original from CAS, some is added by myself. It's little more complex than needed because it also handles the RelayState parameter used for IdP-initiated login.

If you are interested, I can send you the complete code of this method. We have been using for about a year in production.

Best Regards,
   Jarda


Dne pondělí 18. ledna 2016 13:59:48 UTC+1 Andy Warner napsal(a):

Andy 👍

unread,
Jan 19, 2016, 1:06:52 PM1/19/16
to pac4j...@googlegroups.com
Jarda,

Thanks for this,  yeah, looks like I might have to do something like this.  I'd prefer not to customize CAS, but it appears to be required to complete the redirection to the app when using pac4j-saml.
Yes please,  send me what you have and I'll use that as a starting point for customizing this.

Thanks,
Andy
--

Jaroslav Kačer

unread,
Jan 20, 2016, 2:52:04 AM1/20/16
to pac4j-users
Hi Andy!

Here is the complete source code of the ClientAction class.
Just be aware this is for CAS 4.0; if you have a newer version, check the original source and apply the differences one by one. I don't know if this class has changed since 4.0 or not.
Also, you may remove the code related to IdP-initiated login (everything concerning RelayState) and session prolongation (last method). This was not in the original version either.

If there's a problem, just ask :-)

Best Regards,
   Jarda


Dne úterý 19. ledna 2016 19:06:52 UTC+1 Andy Warner napsal(a):
ClientAction.java
Reply all
Reply to author
Forward
0 new messages