Premise
Organizations use multiple services to achieve their deliverables. These services may be built in-house or maybe standard SAAS applications like Gmail, Salesforce etc. Each service requires users of the organization to sign up and remember separate complicated passwords. Eventually, the representatives of each service have to manually handle login and account settings.
Consider traditional authentication involving an organization, user and services
Organization User Services
- The organization is not happy as, if a user leaves the organization or if his role changes, the admin of the organization has to update the same in all of the services that maintain user information separately.
- The user is unhappy as he has to remember multiple logins and passwords for accessing different services attached to the same organization.
- The separate service admins are not happy as apart from the service they provide, they should also handle account creation, password resets of the user, which in their point of view is an overhead. If some authority can confirm to the SAAS applications that the user is valid, then they will be more than happy to provide the services they intend to, rather than maintaining user credentials.
SAML comes in aiming to help companies and services have better authentication processes, without having to manually sign up for every service.
What’s SAML and when should I use it?
SAML, Security Assertion Markup Language, is an open standard data format for exchanging authentication and authorization data between Identity Providers and service providers. It’s a security protocol similar to OpenId, OAuth, Kerberos etc. One of the main use cases SAML addresses is Single-Sign-On (SSO) across services, to offer a simple login experience through a single service.
This method provides great value for both the user and the company.
- Users don’t have to deal with remembering passwords for various applications, while still providing the services the information they need.
- Companies can have a process to identify internal users easily, providing them with the needed data.
- Also, in the case an employee leaves a company, it’s easier to revoke one main account without having to go through and search for multiple accounts for each service this user has had access to.
Parties involved in the authentication
SAML defines 2 parties in the authentication process:
Service provider – The service to which the user wants to log into
Identity provider – A provider who creates, maintains, and manages identity information for users and provides user authentication to other service providers within a federation, such as with web browser profiles
These 2 providers establish trust by passing XML metadata files from one to the other. This is a one-time configuration step. Afterward, when a user tries to access the service, SAMLRequest and SAMLResponse are XML strings that are sent between the two providers and do the actual authentication.
Spring SAML2.0 WebSSO Authentication
The SAML2.0 WebSSO authentication is pretty well described by the following sequence diagram from Wikipedia.
- User hits the Service Provider URL Service provider discovers the IDP to contact for authentication
- Service provider redirects to the corresponding IDP
- User hits the IDP and identifies the user
- IDP redirects to the Login form
- Redirect to Service provider Assertion consumer URL (the URL in Service provider that accepts SAML assertion)
- SP initiates redirect to target resource
- Browser requests for the target resource
- Service provider responds with the requested resource
This blog is aimed at setting up SAML2.0 WEB SSO authentication with Spring security SAML (java based) and assumes the user has a basic understanding of SAML concepts.
Frameworks and libraries
We have used the following frameworks and libraries
- Spring-boot https://spring.io/projects/spring-boot
- Spring-security https://spring.io/projects/spring-security
- Spring-security-saml2-core https://projects.spring.io/spring-security-saml/
The project uses java based configuration of spring security SAML 2.0
Identity provider
For SAML authentication to work we need an identity provider (IdP). We will use Onelogin as our Identity Provider throughout the application: https://www.onelogin.com
The configuration of Onelogin can be done through here
Project setup dependencies
We use the following gradle dependencies:
1 2 3 4 |
compile group: 'org.springframework.security', name: 'spring-security-core', version: "4.2.3.RELEASE" compile group: 'org.springframework.security', name: 'spring-security-web', version: "4.2.3.RELEASE" compile group: 'org.springframework.security', name: 'spring-security-config', version: "4.2.3.RELEASE" compile group: 'org.springframework.security.extensions' , name: 'spring-security-saml2-core' , version : "1.0.2.RELEASE" |
Configurations overview
SAML Entrypoint – Defining when SAML authentication process kicks in
Login – SAML Login configuration
Processing SAML Response – Configuration for processing SAML assertion
Logout – SAML Logout configuration
Displaying SP metadata – Configuration to display Service provider metadata
SP metadata generation – Configuration to auto-generate Service provider metadata
IDP Metadata – Configuration to obtain IDP metadata form resource URL
XML Parsing – Configuration for SAML XML parsing
SAML Binding – Configuration for defining binding parameters for IDP and SP exchange
Context Provider – Configuration for understanding HttpRequest/HttpResponse and delegating handlers to SP/IDP related classes
Web SSO profile – Configurations to handle response for SP and IDP initiated SSO
Spring Security – Authentication Provider configuration
HttpSecurity – Http Configurations
Other Configurations – Other security configurations
Let’s create the main security configuration class, SamlSecurityConfig which will be responsible for all SAML bean declarations and configuration.
1 2 3 4 5 6 7 8 |
@Configuration public class SamlSecurityConfig extends WebSecurityConfigurerAdapter{ @Override protected void configure(HttpSecurity http) throws Exception { } } |
SAML Entrypoint
Let’s build the spring SAML security step by step from this point.
Users will try to access a SAML protected resource and fail. This failure will be handled by Spring security ExceptionTranslationFilter implementation which then will hand over to saml authentication entry point thus starting the saml authentication from your app (Service Provider or SP) to the identity provider (IdP).
Add the following beans to configure entry point:
1 2 3 4 5 6 7 8 9 10 11 12 |
@Bean public SAMLEntryPoint samlEntryPoint() { SAMLEntryPoint samlEntryPoint = new SAMLEntryPoint(); samlEntryPoint.setDefaultProfileOptions(defaultWebSSOProfileOptions()); return samlEntryPoint; } @Bean public WebSSOProfileOptions defaultWebSSOProfileOptions() { WebSSOProfileOptions webSSOProfileOptions = new WebSSOProfileOptions(); webSSOProfileOptions.setIncludeScoping(false); return webSSOProfileOptions; } |
The WebSSOProfileOptions bean allows us to setup parameters of the AuthNRequest. The AuthNRequest is the request sent from SP to IdP for asking user authentication. We can also force authentication from IdP each time the SP sends a new AuthNRequest:
1 |
webSSOProfileOptions.setForceAuthN(true); |
Let’s start configuring HttpSecurity to declare which AuthenticationEntryPoint to call when an authentication exception is triggered:
1 2 3 4 5 6 7 |
@Override protected void configure(HttpSecurity http) throws Exception { http .exceptionHandling() .authenticationEntryPoint(samlEntryPoint()); } |
Let’s add another bean and start initializing the Saml security filter chain i.e the set of all SAML filters which can be involved in SAML operations.
1 2 3 4 5 |
@Bean public FilterChainProxy samlFilter() throws Exception { List<SecurityFilterChain> chains = new ArrayList<>(); return new FilterChainProxy(chains); } |
Displaying SP metadata
Spring security SAML will generate SP metadata according to our SAML configuration.
MetadataDisplayFilter will allow users to download the SP metadata from a specific url.
This metadata will be provided/uploaded to the IDP.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Bean public MetadataDisplayFilter metadataDisplayFilter() { return new MetadataDisplayFilter(); } @Bean public FilterChainProxy samlFilter() throws Exception { List<SecurityFilterChain> chains = new ArrayList<>(); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"), metadataDisplayFilter())); return new FilterChainProxy(chains); } |
The filter is bound to the /saml/metadata url pattern and can be disabled for production environment if we do not want to expose it.
Login
To directly trigger samlEntryPoint, let us add specific login url (/saml/login) to the filter chain that will act as the entry point for SAML requests.
1 2 3 4 5 6 7 8 9 10 |
@Bean public FilterChainProxy samlFilter() throws Exception { List<SecurityFilterChain> chains = new ArrayList<>(); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"), metadataDisplayFilter())); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"), samlEntryPoint())); return new FilterChainProxy(chains); } |
After user logs in, the IDP redirects the SAML response to a configured URL (e.g. «/saml/SSO») called the SAML processing endpoint (often called Assertion Consumer URL) in the SP. This redirection triggers the following filter bean class: SamlWebSSOProcessingFilter. This filter processes arriving SAML messages by delegating to the WebSSOProfile. After the SAMLAuthenticationToken is obtained, authentication providers are asked to authenticate it. Let us configure the filter and add it to the filter chain to handle the authentication response.
Processing SAML Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@Bean public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() { return new SimpleUrlAuthenticationFailureHandler(); } @Bean public SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler() { SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler = new SavedRequestAwareAuthenticationSuccessHandler(); successRedirectHandler.setDefaultTargetUrl("/"); return successRedirectHandler; } @Bean public SAMLProcessingFilter samlWebSSOProcessingFilter() throws Exception { SAMLProcessingFilter samlWebSSOProcessingFilter = new SAMLProcessingFilter(); samlWebSSOProcessingFilter.setAuthenticationManager(authenticationManager()); samlWebSSOProcessingFilter.setAuthenticationSuccessHandler(successRedirectHandler()); samlWebSSOProcessingFilter.setAuthenticationFailureHandler(authenticationFailureHandler()); return samlWebSSOProcessingFilter; } |
and plug the filter into the «/saml/SSO» url.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Bean public FilterChainProxy samlFilter() throws Exception { List<SecurityFilterChain> chains = new ArrayList<>(); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"), metadataDisplayFilter())); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"), samlEntryPoint())); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"), samlWebSSOProcessingFilter())); return new FilterChainProxy(chains); } |
Logout
Logging out can be a two step process depending on where we want the user’s session invalidated
Logout
Global logout
Global logout is a 2 step process, where we clear our SP Spring security context and invalidate any SP cookie so that user is no more authenticated on behalf of our application (let’s call it Spring Logout) and also terminate the sessions of all the SPs with the help of the IDP (SingleLogout)
Spring Logout only
SingleLogout is sometimes not preferred as it terminates all the sessions from all SPs (i.e multiple apps) previously authenticated by the IdP. However, if we want to only logout (Spring Logout) from our app, that is also possible through configuration.
Global logout can be configured with these beans:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
@Bean public SimpleUrlLogoutSuccessHandler successLogoutHandler() { SimpleUrlLogoutSuccessHandler simpleUrlLogoutSuccessHandler = new SimpleUrlLogoutSuccessHandler(); simpleUrlLogoutSuccessHandler.setDefaultTargetUrl(“/”); asdfdfsdsimpleUrlLogoutSuccessHandler.setAlwaysUseDefaultTargetUrl(true); return simpleUrlLogoutSuccessHandler; } @Bean public SecurityContextLogoutHandler logoutHandler() { SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler(); logoutHandler.setInvalidateHttpSession(true); logoutHandler.setClearAuthentication(true); return logoutHandler; } @Bean public SAMLLogoutFilter samlLogoutFilter() { return new SAMLLogoutFilter(successLogoutHandler(), new LogoutHandler[] { logoutHandler() }, new LogoutHandler[] { logoutHandler() }); } @Bean public SAMLLogoutProcessingFilter samlLogoutProcessingFilter() { return new SAMLLogoutProcessingFilter(successLogoutHandler(), logoutHandler()); } |
Now, let us map the logout url (/saml/logout/**) to proper filter and add it to the filter chain.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@Bean public FilterChainProxy samlFilter() throws Exception { List<SecurityFilterChain> chains = new ArrayList<>(); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"), metadataDisplayFilter())); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"), samlEntryPoint())); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"), samlWebSSOProcessingFilter())); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/logout/**"), samlLogoutFilter())); chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SingleLogout/**"), samlLogoutProcessingFilter())); return new FilterChainProxy(chains); } |
SAMLLogoutProcessingFilter: Filter processes arriving SAML Single Logout messages by delegating to the LogoutProfile.
SAMLLogoutFilter : Upon invocation of the filter URL it is determined whether global (termination of all participating sessions) or local (/saml/logout?local=true) (termination of only session running within Spring Security) logout is requested based on request attribute. In case global logout is in question a LogoutRequest is sent to the IDP.
HttpSecurity
Our HttpSecurity looks like this now:
we should configure the following :
1 2 3 4 5 6 7 8 |
@Override protected void configure(HttpSecurity http) throws Exception { //redirect to samlEntryPoint if unauthenticated http .exceptionHandling() .authenticationEntryPoint(samlEntryPoint()); } |
- Disable csrf : IDP and SP belong to different domains, and since IdP will redirect to our SP, we should disable csrf protection as the IdP has no way to know which csrf token it should provide.
- Add the saml filter chain that has been built so far.
- Permit certain URL patterns (/error, /saml/**). These patterns will not need authentication and will allow the users to access the resources without a need to login.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@Override protected void configure(HttpSecurity http) throws Exception { http .exceptionHandling() .authenticationEntryPoint(samlEntryPoint()); http .csrf() .disable(); http .addFilterAfter(samlFilter(), BasicAuthenticationFilter.class); http .authorizeRequests() .antMatchers("/error").permitAll() .antMatchers("/saml/**").permitAll() .anyRequest().authenticated(); } |
SP Metadata generation
The service provider metadata can either be provided as an XML file into the application or generated. Metadata is mandatory to allow IdP know on which SP endpoint redirect to. We can configure MetadataGenerator bean to enable Spring SAML to generate the SP metadata
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@Bean public MetadataGeneratorFilter metadataGeneratorFilter() { return new MetadataGeneratorFilter(metadataGenerator()); } @Bean public MetadataGenerator metadataGenerator() { MetadataGenerator metadataGenerator = new MetadataGenerator(); metadataGenerator.setEntityId(APP_ENTITY_ID); metadataGenerator.setEntityBaseURL(APP_BASE_URL); metadataGenerator.setExtendedMetadata(extendedMetadata()); metadataGenerator.setIncludeDiscoveryExtension(false); metadataGenerator.setKeyManager(keyManager()); return metadataGenerator; } @Bean public ExtendedMetadata extendedMetadata() { ExtendedMetadata extendedMetadata = new ExtendedMetadata(); extendedMetadata.setIdpDiscoveryEnabled(false); extendedMetadata.setSignMetadata(false); return extendedMetadata; } |
APP_BASE_URL –This is the application’s base url after deployment, it varies according to the environment the application is deployed in.
APP_ENTITY_ID – This is the name of the application/ audience field in the application set-up for the IDP
We have disabled IdPDiscovery in ExtendedMetadata Bean as this example is targeted for single SAML IDP. We will cover the keymanager() configuration in the next section.
Let us now add the metadata generator filter to the HttpSecurity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@Override protected void configure(HttpSecurity http) throws Exception { http .exceptionHandling() .authenticationEntryPoint(samlEntryPoint()); http .csrf() .disable(); http .addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class) .addFilterAfter(samlFilter(), BasicAuthenticationFilter.class); http .authorizeRequests() .antMatchers("/error").permitAll() .antMatchers("/saml/**").permitAll() .anyRequest().authenticated(); http .logout() .logoutSuccessUrl("/"); } |
KeyManager
Metadata generation requires a keyManager
1 |
metadataGenerator.setKeyManager(keyManager()); |
keyManager is responsible to encrypt the saml assertion sent to IdP.
A self-signed key and keystore can be generated with the JRE keytool command:
1 |
keytool -genkeypair -alias mykeyalias -keypass mykeypass -storepass samlstorepass -keystore saml-keystore.jks |
1 2 3 4 5 6 7 8 |
@Bean public KeyManager keyManager() { ClassPathResource storeFile = new ClassPathResource("/saml-keystore.jks"); String storePass = "samlstorepass"; Map<String, String> passwords = new HashMap<>(); passwords.put("mykeyalias", "mykeypass"); return new JKSKeyManager(storeFile, storePass, passwords, "mykeyalias"); } |
XML parsing
SAML being XML based protocol, XML parser pools should be initialized to read metadata and assertions that are in XML format.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Bean public VelocityEngine velocityEngine() { return VelocityFactory.getEngine(); } @Bean(initMethod = "initialize") public StaticBasicParserPool parserPool() { return new StaticBasicParserPool(); } @Bean(name = "parserPoolHolder") public ParserPoolHolder parserPoolHolder() { return new ParserPoolHolder(); } |
SAML Binding configuration
SAML Binding that we use depends on the IDP specifications. We use POST and Redirect bindings with respect to our configuration in Onelogin and initialize SAMLProcessorImpl accordingly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@Bean public HTTPPostBinding httpPostBinding() { return new HTTPPostBinding(parserPool(), velocityEngine()); } @Bean public HTTPRedirectDeflateBinding httpRedirectDeflateBinding() { return new HTTPRedirectDeflateBinding(parserPool()); } @Bean public SAMLProcessorImpl processor() { Collection<SAMLBinding> bindings = new ArrayList<>(); bindings.add(httpRedirectDeflateBinding()); bindings.add(httpPostBinding()); return new SAMLProcessorImpl(bindings); } |
Other configurations
We initialize HTTPClient with multithreaded connection manager, initialize saml logger and more importantly SAML BootStrap which is responsible for the initialization of SAML library and is automatically called as part of Spring initialization.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Bean public HttpClient httpClient() { return new HttpClient(multiThreadedHttpConnectionManager()); } @Bean public MultiThreadedHttpConnectionManager multiThreadedHttpConnectionManager() { return new MultiThreadedHttpConnectionManager(); } @Bean public static SAMLBootstrap SAMLBootstrap() { return new SAMLBootstrap(); } @Bean public SAMLDefaultLogger samlLogger() { return new SAMLDefaultLogger(); } |
Context provider
SAMLContextProviderImpl is responsible for parsing HttpRequest/Response and determining which local entity (IDP/SP) is responsible for its handling.
This configuration is for the application that is not behind a Reverse Proxy.
1 2 3 4 |
@Bean public SAMLContextProviderImpl contextProvider() { return new SAMLContextProviderImpl(); } |
Alternatively, SAMLContextProviderLB can be used, which is a Context provider that overrides request attributes with values of the load-balancer or reverse-proxy in front of the local application. The settings help to provide correct redirect URls and verify destination URLs during SAML processing.
Web SSO profile
We need beans for configuring WebSSO profile and logout. We use default spring saml provided implementation
WebSSOProfileConsumer Class is able to process Response objects returned from the IDP after SP initialized SSO or unsolicited response from IDP.
WebSSOProfile Class implements WebSSO profile and offers capabilities for SP initialized SSO and process Response coming from IDP or IDP initialized SSO. HTTP-POST and HTTP-Redirect bindings are supported.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// SAML 2.0 WebSSO Assertion Consumer @Bean public WebSSOProfileConsumer webSSOprofileConsumer() { return new WebSSOProfileConsumerImpl(); } // SAML 2.0 Web SSO profile @Bean public WebSSOProfile webSSOprofile() { return new WebSSOProfileImpl(); } @Bean public SingleLogoutProfile logoutprofile() { return new SingleLogoutProfileImpl(); } |
SingleLogoutProfileImplImplementation of the SAML 2.0 Single Logout profile.
IdP metadata
The IDP metadata provides the means of contacting it through metadata.
It can either be downloaded from the IDP (Onelogin) , or if we provide the resource URL from where the metadata can be downloaded, the Spring SAML configuration does it for us.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@Bean public ExtendedMetadataDelegate idpMetadata() throws MetadataProviderException, ResourceException { Timer backgroundTaskTimer = new Timer(true); HTTPMetadataProvider httpMetadataProvider = new HTTPMetadataProvider(backgroundTaskTimer, new HttpClient(),ONELOGIN_METADATA_URL.concat(getAppId())); httpMetadataProvider.setParserPool(parserPool()); ExtendedMetadataDelegate extendedMetadataDelegate = new ExtendedMetadataDelegate(httpMetadataProvider , extendedMetadata()); extendedMetadataDelegate.setMetadataTrustCheck(true); extendedMetadataDelegate.setMetadataRequireSignature(false); return extendedMetadataDelegate; } @Bean @Qualifier("metadata") public CachingMetadataManager metadata() throws MetadataProviderException, ResourceException { List<MetadataProvider> providers = new ArrayList<>(); providers.add(idpMetadata()); return new CachingMetadataManager(providers); } |
ONELOGIN_METADATA_URL.concat(getAppId()) –The IDPs metadata URL followed by the unique app Id for the application set in the IDP
Spring security
Now let’s add some classic Spring Security configuration: – AuthenticationProvider. The authentication provider is capable of verifying the validity of a SAMLAuthenticationToken and in case the token is valid to create an authenticated UsernamePasswordAuthenticationToken.
AuthenticationProvider
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Bean public SAMLAuthenticationProvider samlAuthenticationProvider() { SAMLAuthenticationProvider samlAuthenticationProvider = new SAMLAuthenticationProvider(); samlAuthenticationProvider.setForcePrincipalAsString(false); return samlAuthenticationProvider; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .authenticationProvider(samlAuthenticationProvider()); } |
Conclusion
We have completed SAML configuration in Java and the web urls in the application now are authenticated through SAML.
You can find sample project here https://github.com/lakshmiabinaya/saml-java
In the next section of the blog, we will address how to authenticate the REST APIs in the application ie what if your application uses SAML for web pages and also authentication via REST for its APIs https://blog.imaginea.com/using-rest-with-saml-java/
Very useful article, can you please specify the information sources that you have refereed for this article. It will be highly helpful for me as I want to dig more.
Thank you v m. I am thankful to you for this very useful info. Kudos !!
Hi, I just wanted to let you know that this article really helped me alot. Its a very well explained one! Kudos!
Nice article. Very helpful..thank you!
please can you provide the link authentication mechanism for its REST APIs with SAML
Hello,
Thanks for the amazing tutorial. I do have a question however.
How can I secure the endpoints based on Roles. I return Groups as a claim in the SAML response, but using
@PreAuthorize(“hasRole(‘ROLE_USER’)”) does not work for example.
Very Nice article well explained. Do you have a maven version of this example or even a pom.xml file
Great explanation! Thank you!
Thanks!
Nice article. Very Helpful.
Thanks
Thanks!
Wonderful job!! Could have been more illustrative by including the following:
1)the process for fetching details like appid, entityid for a given IDP , and
2)snapshots of the working application
Thanks! Will try to add
Where is the next section of this blog?
I want to know how to combine SAML with other authentication mechanisms.
Great article. Very helpful. I do have a question though.
The AppId and Entity Id mentioned in the application properties file. Is the AppId and Entity Id of the SP mentioned in the IDP or is it the AppId and Entity Id of the IDP.
Thanks in advance.
The IDs are of the service provider
Pingback: Using REST with SAML in Java – experience@imaginea
Nice article. If we want to implement redirect to a specific page after successful login, is successRedirectHandler() method to be implemented as successRedirectHandler.setDefaultTargetUrl(“http://somepreviousurl”); I tried this. Its not working
Very good article.
It is very close to our use case and thanks to your detailed description of every step it was easy for us to understand and adapt it to our needs.
Many thanks and best regards!