Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I supply a jks file for saml decryption? #29

Open
wccropper opened this issue Mar 15, 2022 · 2 comments
Open

How do I supply a jks file for saml decryption? #29

wccropper opened this issue Mar 15, 2022 · 2 comments
Labels
documentation Improvements or additions to documentation

Comments

@wccropper
Copy link

I see there are config options for the application.yaml for saml+jks. I am using Azure AD Enterprise application. The communication is working as I am prompted to login and the correct entity-id is being returned (firefox SAML_tracer). The current error is:

Caused by: org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:265)
at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:88)
... 102 more
Caused by: org.opensaml.xml.validation.ValidationException: Signature is not trusted or invalid

I believe I need to provide as java keystore of the saml signing cert from Azure. I have created this and stored it as a secret, but do no see a way to pass this to the sp-shinyproxy containers.

@LEDfan
Copy link
Member

LEDfan commented Mar 17, 2022

Hi

This is possible using the kubernetesPodTemplateSpecPatches field of the shinyproxy CRD. First you have to create a configmap containing the keystore. You can do this with a typical yaml file, or you can use kustomize for it:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
 - name: saml-keystore
   files:
    - shinyproxy-saml-keystore.jks

Next, you can mount the configmap into the ShinyProxy pod, using the kubernetesPodTemplateSpecPatches field, for example:

apiVersion: openanalytics.eu/v1alpha1
kind: ShinyProxy
metadata:
  name: shinyproxy
spec:
  proxy:
    title: Open Analytics Shiny Proxy
    logo-url: https://www.openanalytics.eu/shinyproxy/logo.png
    landing-page: /
    heartbeat-rate: 10000
    heartbeat-timeout: 60000
    port: 8080
    authentication: saml
    saml:
        keystore: /opt/shinyproxy/saml-keystore/keystore.jks
    specs:
    - id: 01_hello
      display-name: Hello Application
      description: Application which demonstrates the basics of a Shiny app
      container-cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
      container-image: openanalytics/shinyproxy-demo
      access-groups: [scientists, mathematicians]
    - id: 06_tabsets
      container-cmd: ["R", "-e", "shinyproxy::run_06_tabsets()"]
      container-image: openanalytics/shinyproxy-demo
      access-groups: scientists
    kubernetesPodTemplateSpecPatches: |
      - op: add
        path: /spec/volumes/-
        value:
          name: saml-keystore
          configMap:
            name: saml-keystore
      - op: add
        path: /spec/containers/0/volumeMounts/-
        value:
          name: saml-keystore
          mountPath: /opt/shinyproxy/saml-keystore/keystore.jks
          subPath: shinyproxy-saml.jks

  logging:
    file:
      name: shinyproxy.log

Currently this is not very well documented, therefore I'll keep this issue open to remind us of improving the documentation.

@LEDfan LEDfan added the documentation Improvements or additions to documentation label Mar 17, 2022
@wccropper
Copy link
Author

Thanks for this. I was unable to look at it until today and it doesn't seem to work. My config blocks look like:

spec:
  proxy:
    authentication: saml
    saml:
      idp-metadata-url: redacted
      app-entity-id: redacted
      app-base-url: redacted
      roles-attribute: http://schemas.microsoft.com/ws/2008/06/identity/claims/role
      logout-method: local
      force-authn: true
      keystore: /opt/shinyproxy/saml-keystore/keystore.jks
      keystore-password: passwd
      encryption-cert-name: shinyapps-saml-pem
  kubernetesPodTemplateSpecPatches: |
    - op: add
      path: /spec/volumes/-
      value:
        name: saml-keystore
        configMap:
          name: saml-keystore
    - op: add
      path: /spec/containers/0/volumeMounts/-
      value:
        name: saml-keystore
        mountPath: /opt/shinyproxy/saml-keystore/keystore.jks
        subPath: shinyapps-saml-keystore.jks

The error block is:

2022-04-04 16:27:02.629  INFO 1 --- [  XNIO-2 task-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms
2022-04-04 16:27:02.635  INFO 1 --- [  XNIO-2 task-1] o.s.s.s.m.MetadataGeneratorFilter        : No default metadata configured, generating with default values, please pre-configure metadata for production use
2022-04-04 16:27:02.648 ERROR 1 --- [  XNIO-2 task-1] io.undertow.request                      : UT005023: Exception handling request to /actuator/health/liveness

java.lang.NullPointerException: null
	at org.opensaml.xml.security.credential.KeyStoreCredentialResolver.resolveFromSource(KeyStoreCredentialResolver.java:127) ~[xmltooling-1.4.6.jar!/:na]
	at org.opensaml.xml.security.credential.AbstractCriteriaFilteringCredentialResolver.resolve(AbstractCriteriaFilteringCredentialResolver.java:57) ~[xmltooling-1.4.6.jar!/:na]
	at org.opensaml.xml.security.credential.AbstractCredentialResolver.resolveSingle(AbstractCredentialResolver.java:30) ~[xmltooling-1.4.6.jar!/:na]
	at org.opensaml.xml.security.credential.AbstractCredentialResolver.resolveSingle(AbstractCredentialResolver.java:26) ~[xmltooling-1.4.6.jar!/:na]
	at org.springframework.security.saml.key.JKSKeyManager.resolveSingle(JKSKeyManager.java:171) ~[spring-security-saml2-core-1.0.10.RELEASE.jar!/:1.0.10.RELEASE]
	at org.springframework.security.saml.key.JKSKeyManager.getCredential(JKSKeyManager.java:191) ~[spring-security-saml2-core-1.0.10.RELEASE.jar!/:1.0.10.RELEASE]
	at org.springframework.security.saml.metadata.MetadataGenerator.getServerKeyInfo(MetadataGenerator.java:205) ~[spring-security-saml2-core-1.0.10.RELEASE.jar!/:1.0.10.RELEASE]
	at org.springframework.security.saml.metadata.MetadataGenerator.buildSPSSODescriptor(MetadataGenerator.java:329) ~[spring-security-saml2-core-1.0.10.RELEASE.jar!/:1.0.10.RELEASE]
	at org.springframework.security.saml.metadata.MetadataGenerator.generateMetadata(MetadataGenerator.java:189) ~[spring-security-saml2-core-1.0.10.RELEASE.jar!/:1.0.10.RELEASE]
	at org.springframework.security.saml.metadata.MetadataGeneratorFilter.processMetadataInitialization(MetadataGeneratorFilter.java:127) ~[spring-security-saml2-core-1.0.10.RELEASE.jar!/:1.0.10.RELEASE]
	at org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:86) ~[spring-security-saml2-core-1.0.10.RELEASE.jar!/:1.0.10.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.9.RELEASE.jar!/:5.3.9.RELEASE]
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.3.9.RELEASE.jar!/:5.3.9.RELEASE]
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.3.9.RELEASE.jar!/:5.3.9.RELEASE]
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) ~[undertow-core-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) ~[undertow-core-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) ~[undertow-core-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) ~[undertow-core-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) ~[undertow-core-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) ~[undertow-core-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99) ~[undertow-servlet-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:387) ~[undertow-core-2.2.8.Final.jar!/:2.2.8.Final]
	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:841) ~[undertow-core-2.2.8.Final.jar!/:2.2.8.Final]
	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) ~[jboss-threads-3.1.0.Final.jar!/:3.1.0.Final]
	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019) ~[jboss-threads-3.1.0.Final.jar!/:3.1.0.Final]
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558) ~[jboss-threads-3.1.0.Final.jar!/:3.1.0.Final]
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1423) ~[jboss-threads-3.1.0.Final.jar!/:3.1.0.Final]
	at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280) ~[xnio-api-3.8.4.Final.jar!/:3.8.4.Final]
	at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]

I have verified the jks is mounted and I can use keytool within the pod to access the cert.

Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants