SAML Authentication Help

356 views
Skip to first unread message

Dave Sims

unread,
Aug 15, 2018, 10:43:41 PM8/15/18
to cBioPortal for Cancer Genomics Discussion Group
Hi,
I have been trying to get SAML working on a Docker instance of cBioPortal for a few days now and have run out of options.  Was hoping for some advice here.  Interestingly, I did get one Docker instance working, but was unable to ever replicate that success again!  

I have followed the instructions to use OneLogin as the provider, and got it working on one local test instance (let's call it my Macbook).  However, when I tried to deploy it to a server (an Amazon AWS instance), it didn't work (I actually copies the same metadata.xml, properties file, etc. and it still didn't work!).  I get re-directed to OneLogin as expected, login successfully, and then get re-directed back to cBioPortal.  But, then I'm getting a "Access to this portal is only available to authorized users" error.  Clicking the "Sign In" button just repeats that process.  

Working with our internal folks, who prefer Okta, I tried to set up SAML with that tool, and had the same result; it works on one local instance (the same one that worked with OneLogin), but won't work anywhere else (have tried two other systems, including another Mac system, with the same issues).  I'm getting the same exact problem where I'm getting the unauthorized to access error.

I'm using the cBioPortal 1.12.1 image, and have also tried 1.14.1, with the same problem.  Just now, I tried by combining a new cbioportal Docker container instance with the cbioDB Docker container on the system that works, and Okta authentication is working.  So, the problem must reside in the database, but as far as I can see it's all the same.  I can verify that cbioportal.users has the same one user with the same EMAIL, NAME, and ENABLED status, and cbioportal.authorities also has the same EMAIL and AUTHORITY (cbioportal:ALL).  Is there another table or something that's causing this?  I'm happy to attach any log files, config / meta files, etc, but I'm not sure what to attach to be honest as I can't seem to find a smoking gun error in any of them.  

Also from seeing some messages here and whatnot, I'm wondering if Keycloak is preferred to a SAML SSO method.  Should I be using something else (i.e. is SAML deprecated?) or can I get it working with SAMP (no matter what IdP)?

Thanks in advance for your help!!
Dave Sims

Benjamin Gross

unread,
Aug 16, 2018, 10:55:08 AM8/16/18
to Dave Sims, cBioPortal for Cancer Genomics Discussion Group
Hi Dave,

It sounds like you are doing everything right.  Users and Authorities are the only tables you need to work with.  Its a reach, but my first thought is that maybe the token coming back from OneLogin or Okta is not getting through or returning with a different credential than what is in the database (doesn't explain the one local test that succeeded).  Before sending any logs, can you add the following line to your log4j.properties:

log4j.logger.org.springframework.security=DEBUG

This should add extra security entries in the log.  Hopefully, this will shed some light on the situation.

As to using Keycloak over SAML - those are two separate questions.  You can use Keycloak as a way to manage cBioPortal users and authorities. If you did this, you wouldn't be relying on the user and authorities tables in the cBioPortal database.  As it happens, Keycloak can speak SAML and other protocols if you need to authenticate users against an institutional identity provider over a certain protocol and this is really the answer to question of using SAML or not.  You don't need to use SAML unless its required for authentication.  The cBioPortal uses the spring-security library for authentication/authorization, there is support for OAuth2, LDAP/AD, SAML).

Let us know how it goes.

Thanks,
Benjamin

--
You received this message because you are subscribed to the Google Groups "cBioPortal for Cancer Genomics Discussion Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cbioportal+...@googlegroups.com.
To post to this group, send email to cbiop...@googlegroups.com.
Visit this group at https://groups.google.com/group/cbioportal.
To view this discussion on the web visit https://groups.google.com/d/msgid/cbioportal/c3bcf2f4-8f21-4250-bf96-d4f438bac570%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

messer...@gmail.com

unread,
Aug 17, 2018, 9:26:28 AM8/17/18
to cBioPortal for Cancer Genomics Discussion Group
Hi Dave,

looks like you already solved the hardest part and got the authentication to work!

From my experience, the documentation works if the docker containers run on the same host, once you have cbioportal and e.g. keycloak on different servers, there are some caveats to work through which are inadequately described in the documentation. But your problems should be easily solvable with some guidance.

1) Turn on debugging like suggested and read the logs carefully.
2) Try the SAML tracer plugin for Firefox (this helped me very much)

Here are the problems that I faced:
a) you need to configure keycloak to return the right attributes (IIRC cbioportal looks for "email", but keycloak by default returns the value with a different key)
(Our setup currently uses the authorization table in the db instead of keycloak attributes, I can make the code for that available. Discussion here https://github.com/cBioPortal/cbioportal/issues/3061)
b) you might need to change the SAML context provider if you serve over HTTPS, this was a pain to get working.


Dave Sims

unread,
Aug 17, 2018, 1:05:51 PM8/17/18
to cBioPortal for Cancer Genomics Discussion Group
Hi Benjamin,

I don't think my reply showed up here, though I see it my email.  So, I wanted to post this here for people.  I think I've fully figured this out (though in my original response to you, I had only figured out half of it)!

I thought I had looked through those logs, but I think they were so dense that I missed things the first time around.  As it turns out there are two different problems, one that I can solve (and will post here for future reference in case others run into it), and one that I don't understand, but think I have worked out now.

The first problem, which I experienced on my localhost instance is that the date and time of the Docker instance can start to drift away from the correct current time.  If it differs by more than 60 seconds from the current time, then the SAML transaction will be invalidated and an error will be generated:

2018-08-16 19:36:04 [http-nio-8080-exec-3] DEBUG org.springframework.security.saml.SAMLAuthenticationProvider - Error validating SAML message
org.opensaml.common.SAMLException: Response issue time is either too old or with date in the future, skew 60, time 2018-08-16T19:07:25.950Z

The simple solution (since I couldn't figure out an easy way to sync the time servers - standard Unix commands don't seem to work in this environment) is to just restart Docker.  Upon restart, the date and time are synced with the host and everything works fine!  I wonder if the folks managing the Docker version of this might be able to work a fix into the next release? 

The second problem occurs only on my Amazon AWS instance, and the full error is:

2018-08-16 20:18:30 [http-nio-8080-exec-19] INFO  org.springframework.security.saml.log.SAMLDefaultLogger - AuthNResponse;FAILURE;129.43.39.165;cbioportal;http://www.okta.com/e
xkfxfacfvZEf45TI0h7;;;org.opensaml.common.SAMLException: Intended destination http://ec2-34-232-124-235.compute-1.amazonaws.com/cbioportal/saml/SSO doesn't match any of the end
point URLs for profile urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser
at org.springframework.security.saml.websso.AbstractProfileBase.verifyEndpoint(AbstractProfileBase.java:248)
at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:148)
at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:82)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:84)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.filters.CorsFilter.handleNonCORS(CorsFilter.java:441)
at org.apache.catalina.filters.CorsFilter.doFilter(CorsFilter.java:169)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1468)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)

My localhost mapped port was always 8081 as per the instructions, but this instance is actually just using the default port 80 since there didn't seem to be a reason to map it otherwise.  On a whim, I just decided to explicitly list port 80 in my SSO URL settings in Okta (i.e. the URL is now: http://ec2-34-232-124-235.compute-1.amazonaws.com:80/cbioportal/saml/SSO) thinking that maybe it was enough to cause the mis-match. Turns out that it worked!  I'm not sure why port 80 wouldn't be considered the default if one is not explicitly indicated, but it turns out that you must put the port in the SSO URL or it won't work. 

Hopefully these two lessons will help someone else in the future when they're trying to set this up!

d

Benjamin Gross

unread,
Aug 20, 2018, 12:35:45 PM8/20/18
to Dave Sims, cBioPortal for Cancer Genomics Discussion Group
HI Dave,

Glad to hear you've figured it out.

We had a similar situation with date/time drift here at MSK.  I solved it by setting a skew time in the following spring security configuration file:


I think 60 seconds is the default.  

    <!-- SAML 2.0 WebSSO Assertion Consumer -->
    <b:bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl">
      <b:property name="responseSkew" value="TIME_IN_SECONDS"/>
    </b:bean>

Thanks for the default port info.

Let us know if you have any more questions.

-B
Reply all
Reply to author
Forward
0 new messages