Palak Shah
Palak Shah

Reputation: 11

Okta-api -Issue using Spring-security SAML with CSRF

I have gone thru the steps listed in the document -

https://developer.okta.com/blog/2017/03/16/spring-boot-saml#run-the-app-and-login-with-okta

Everything works fine and I see SAML response getting generated and reditection happening to Application from OKTA but when the request reaches the application, I get this error-

type=Forbidden, status=403). Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.

I have tried disabling csrf but then it goes in infinite loop with SAML redirection.

Here's SecurityConfiguration.java-

package com.example;

import static org.springframework.security.extensions.saml2.config.SAMLConfigurer.saml;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Value("${security.saml2.metadata-url}")
    String metadataUrl;

    @Value("${server.ssl.key-alias}")
    String keyAlias;

    @Value("${server.ssl.key-store-password}")
    String password;

    @Value("${server.port}")
    String port;

    @Value("${server.ssl.key-store}")
    String keyStoreFilePath;

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/saml*").permitAll()
                .anyRequest().authenticated()
                .and()
            .apply(saml())
                .serviceProvider()
                    .keyStore()
                        .storeFilePath("saml/keystore.jks")
                        .password(this.password)
                        .keyname(this.keyAlias)
                        .keyPassword(this.password)
                        .and()
                    .protocol("https")
                    .hostname(String.format("%s:%s", "10.200.10.10", this.port))
                    .basePath("/")
                    .and()
                .identityProvider()
                .metadataFilePath(this.metadataUrl);
    }
}

Any suggestion is appreciated.

Upvotes: 1

Views: 2297

Answers (3)

Maclean Pinto
Maclean Pinto

Reputation: 1135

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**").authorizeRequests().antMatchers("/saml").permitAll()
                .anyRequest().authenticated().and().csrf().csrfTokenRepository(getCsrfTokenRepository());
    }

    private CsrfTokenRepository getCsrfTokenRepository() {
        CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
        tokenRepository.setCookiePath("/");
        return tokenRepository;
    }

Add CSRF cookie. In the front end, if you are using Angular just import HttpClientXsrfModule. This would fetch the cookie value and set request header X-XSRF-TOKEN header

@Note : The configuration for saml login with still be the same. The above code shows, how to add csrf token.

Upvotes: 0

Palak Shah
Palak Shah

Reputation: 11

This issue is resolved.. I did couple of things-

In OKTA added destination url same as Single sign on URL- https://localhost:8443/saml/SSO

Also, on Spring side, I have disabled CSRF protection in SecurityConfiguration-

http.csrf().disable();

But really the issue was wrong destination url.

Upvotes: 0

Matt Raible
Matt Raible

Reputation: 8634

The only difference I see in your code vs. my blog post is the following line:

.hostname(String.format("%s:%s", "10.200.10.10", this.port))

Do things work if you change it to the following?

.hostname(String.format("%s:%s", "localhost", this.port))

Upvotes: 0

Related Questions