Skip to content

SpringSAMLAuth

Jim Potter edited this page Dec 13, 2021 · 17 revisions

Adding Spring security

This is the tricky bit. There are a few points here...

  • this is not easy to test without an IdP to hand
  • Its not easy to get an IdP working
  • If this doesn't work, its hard to tell if its the IdP or sP going wrong.

Code available here: https://github.com/jim-reespotter/SpringBootSAML/tree/BasicSAML

Prereqs:

Simple SpringBoot webapp is working

How SAML works reminder

The plan with SAML is that you can pass authentication off to a trusted 3rd party. This should in theory make you webapp simpler because it doesn't have to do very much it terms of authentication at all. SAML is designed to allow users in a directory of some description owned by one organisation access resources from another organisation without too much of the users' data being shared to the resource organisation. To do this the organisations exchange metadata (web endpoints and public keys) so they can verify each other and communicate securely. The 2 endpoints (identity and resource) never contact each other directly - all messages are given to the browser to pass over (generally via 302HTTP messages)

Steps:

Security dependencies:

  • Add Spring security bits to build.gradle: dependencies:
    • spring-security-config
    • spring-security-saml2-service-provider (should still run but now present a login page)

Base security class

(SAMLSecurityConfig.java, application.yml)

  • Rename src/main/resources/application.properties to application.yml
  • Add a new java class under src/main/java/stuff/things/SpringBootSAML.java
    • annotate it @EnableWebSecurity
    • extend it with WebSecurityConfigurerAdapter
    • add imports (from org.springframework.security.config.annotation.web.configuration)
    • add a new method:
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().permitAll();
    }

(re-run it, should now present index page again, no login)

Add necessary SAML keys, inform sP of the details of the IdP

We need to generate a public and private key for SAML signing in src/main/resources/credentials/ - change to that folder and run:

openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout private.key -out public.cer (Answer the questions as you will, they make no difference here)

Add the following to application.yml:

spring:
  security:
    saml2:
      relyingparty:
        registration:
          MySAMLApp:
            signing:
              credentials:
                - private-key-location: "classpath:credentials/private.key"
                  certificate-location: "classpath:credentials/public.cer"
            identityprovider:
              metadata-uri: https://samltest.id/saml/idp

Key points here:

  • metadata-uri needs to exist - it will pull the metadata from this site on startup On a good day this will still work as an unauthenticated app.

Configure the metadata provider endpoint

In this step we create a URL from which you can retrieve this sP's metadata (SAMLSecurityConfig.java): Add an autowired attribute to the SAMLSecurityconfig class:

    @Autowired
    RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;

Edit the configure method in SAMLSecurityConfig:

    protected void configure(HttpSecurity http) throws Exception {

        RelyingPartyRegistrationResolver relyingPartyRegistrationResolver =
        new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository);

        Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());
        
        http
            .saml2Login(withDefaults())     // needs import static org.springframework.security.config.Customizer.withDefaults;
                .addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class)
                .antMatcher("/**")
            .authorizeRequests()
                .anyRequest()
                .permitAll();
    }

This configures the metadata endpoint at: http://localhost:8080/saml2/service-provider-metadata/MySAMLApp - this url will present you with the XML metadata required by the IdP (Where MySAMLApp will match application.yml relyingparty.registration) restart the applciation - its also useful to debu at this point: gradle bootRun --debug http://localhost:8080 should still take you to your index page, but you can force authentication with: http://localhost:8080/saml2/authenticate/MySAMLApp (which will fail probably)

Linking in the IdP

you now are in a posistion to exchange metadata (actually, the sP has already pulled the IdP's metadata as defined in application.yml when it started up)

Securing content

Edit the http. stanza in SAMLSecurityConfig.java/configure:

  • replace permitAll() with authenticated() Restart the SrpingBoot app, browse to http://localhost:8080 - you should be taken to an authentication page, then back to index.html

Next up:

Clone this wiki locally