Search code examples
oktaspring-security-saml2

Spring boot and Okta SAML2


I like the idea of using spring-security-saml2-service-provider - from of docs: https://docs.spring.io/spring-security/reference/5.6.0-RC1/servlet/saml2/index.html Instead of spring-security-saml2-core it looks way less boilerplate, but I catch 400 response when I send App Embed Link from Okta admin app. Through debug it seems that

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        AbstractSaml2AuthenticationRequest authenticationRequest = this.authenticationRequestResolver.resolve(request);
        if (authenticationRequest == null) {
            filterChain.doFilter(request, response);..}

can't resolve the incoming request,but I am not sure whether it's related. My yml config:

 security:
    saml2:
      relyingparty:
        registration:
          okta:
            identityprovider:
              entity-id: http://www.okta.com/exk1juy5xrR5BsW44697
              verification.credentials:
                - certificate-location: "classpath:saml/okta.cert"
              singlesignon.url: https://trial-8410773.okta.com/app/trial-8410773_templatemanager_2/exk1juy5xrR5BsW44697/sso/saml
              singlesignon.sign-request: false
              assertingparty.metadata-uri: https://trial-8410773.okta.com/app/trial-8410773_templatemanager_2/exk1juy5xrR5BsW44697/sso/saml/metadata

My Okta config:

GENERAL
Single Sign On URLhttp://localhost:8080/api/v1/saml2/SSO
Requestable SSO URLsURLIndex
http://localhost:8080/api/v1/saml2/SSO0Recipient URLhttp://localhost:8080/api/v1/saml2/SSODestination URLhttp://localhost:8080/api/v1/saml2/SSOAudience Restrictionhttp://localhost:8080/saml/metadata

Also I provide endpoint for saml authentication:

@RequestMapping(SsoAuthenticationController.BASE_NAME)
public interface SsoAuthenticationController {

    final String BASE_NAME = "/v1/saml2/SSO";

    @GetMapping("/")
    public ResponseEntity<HttpStatus> index( Saml2AuthenticatedPrincipal principal) ;
}

Actual security config:

http.cors()
        .and()
        .csrf()
        .disable()
        .authorizeRequests()
        .antMatchers(SECURITY_WHITELIST)
        .permitAll()
        .anyRequest()
        .authenticated()
        /*.and()
        .httpBasic()
        .and()
        .exceptionHandling()
        .authenticationEntryPoint(authenticationEntryPoint).and().sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)*/
        .and()
        .saml2Login(Customizer.withDefaults());

Here is Saml interceptor's logs for google chrome: https://pastebin.com/Be3NZe5B

Any ideas?


Solution

  • I created a Spring Boot 3 + SAML example with Okta recently. Hopefully, these instructions help.

    Create a Spring Boot app using start.spring.io. Select the following options:

    • Project: Gradle
    • Spring Boot: 3.0.0 (SNAPSHOT)
    • Dependencies: Spring Web, Spring Security, Thymeleaf

    Add src/main/java/com/example/demo/HomeController.java to populate the authenticated user's information.

    package com.example.demo;
    
    import org.springframework.security.core.annotation.AuthenticationPrincipal;
    import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class HomeController {
    
        @RequestMapping("/")
        public String home(@AuthenticationPrincipal Saml2AuthenticatedPrincipal principal, Model model) {
            model.addAttribute("name", principal.getName());
            model.addAttribute("emailAddress", principal.getFirstAttribute("email"));
            model.addAttribute("userAttributes", principal.getAttributes());
            return "home";
        }
    
    }
    

    Create a src/main/resources/templates/home.html file to render the user's information.

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
          xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
    <head>
        <title>Spring Boot and SAML</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    </head>
    <body>
    
    <h1>Welcome</h1>
    <p>You are successfully logged in as <span sec:authentication="name"></span></p>
    <p>Your email address is <span th:text="${emailAddress}"></span>.</p>
    <p>Your authorities are <span sec:authentication="authorities"></span>.</p>
    <h2>All Your Attributes</h2>
    <dl th:each="userAttribute : ${userAttributes}">
        <dt th:text="${userAttribute.key}"></dt>
        <dd th:text="${userAttribute.value}"></dd>
    </dl>
    
    <form th:action="@{/logout}" method="post">
        <button id="logout" type="submit">Logout</button>
    </form>
    
    </body>
    </html>
    

    Create a src/main/resources/application.yml file to contain your metadata URI.

    spring:
      security:
        saml2:
          relyingparty:
            registration:
                assertingparty:
                  metadata-uri: <your-metadata-uri>
    

    Then, change build.gradle to use thymeleaf-extras-springsecurity6 instead of thymeleaf-extras-springsecurity5 and add Spring Security SAML's dependency:

    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
    implementation 'org.springframework.security:spring-security-saml2-service-provider'
    

    To get the metadata URI from Okta, log in to your account and go to Applications > Create App Integration. Select SAML 2.0 and click Next. Name your app something like Spring Boot SAML and click Next.

    Use the following settings:

    • Single sign on URL: http://localhost:8080/login/saml2/sso/okta
    • Use this for Recipient URL and Destination URL: ✅ (the default)
    • Audience URI: http://localhost:8080/saml2/service-provider-metadata/okta

    Then click Next. Select the following options:

    • I'm an Okta customer adding an internal app
    • This is an internal app that we have created

    Select Finish.

    Okta will create your app, and you will be redirected to its Sign On tab. Scroll down to the SAML Signing Certificates and go to SHA-2 > Actions > View IdP Metadata. You can right-click and copy this menu item's link or open its URL. Copy the resulting link to your clipboard. It should look something like the following:

    https://dev-13337.okta.com/app/<random-characters>/sso/saml/metadata
    

    Go to your app's Assignment tab and assign access to the Everyone group.

    Paste your metadata URI in to your application.yml file. Start the app using ./gradlew bootRun and open http://localhost:8080 in your favorite browser. You should be redirected to login.