Integration von Microsoft Entra SSO SAML in Spring BootJava

Java-Forum
Anonymous
 Integration von Microsoft Entra SSO SAML in Spring Boot

Post by Anonymous »

Ich habe ein Problem mit der Integration meiner Entra in meine Spring -Boot -Anwendung für SSO mit SAML. Meine Umgebung ist Spring Boot 3.4.3, Java 17. Ich habe einen Benutzer auf Entra erstellt, um SSO zu implementieren, und der Anmeldeteil funktioniert gut, aber wenn er von der Antwort -URL von der Antwort -URL in meine Anwendung umgeleitet wird, sollte die Spring Security das Authentifizierungsobjekt mit geeigneten Werten erstellen, in denen ich sie als Null empfehle. Ich habe angepasstes Authentifizierungsobjekt mit samlresponse aus den von Debugger validierten Params erstellt, die ich durch Debugger validiert habe, aber das SAML2AuthenticationToken, wenn er erstellt wurde, hat erneut Nullwerte.

Code: Select all

import jakarta.servlet.http.HttpServletRequest;
import org.opensaml.saml.saml2.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import java.util.Base64;
import java.util.List;

@RestController
@RequestMapping("/saml")
public class SamlController {

@Autowired
private RelyingPartyRegistrationRepository repository;

@PostMapping("/acs")
public String processSamlResponse(HttpServletRequest request) throws Exception {
// Get the SAML Response from the request
String samlResponseFromRequest = request.getParameter("SAMLResponse");

if (samlResponseFromRequest == null) {
return "No SAML Response received";
}

// Decode the Base64 encoded SAML response
String decodedResponse = new String(Base64.getDecoder().decode(samlResponseFromRequest));

// Delegate the response parsing and authentication to Spring Security's built-in mechanism
// Spring Security will automatically create the Saml2AuthenticationToken
Saml2AuthenticationToken token = parseSamlResponse(decodedResponse);

if (token.getPrincipal() == null) {
return "SAML response parsing failed, no principal found.";
}

// Set the Authentication object in the SecurityContext
Authentication authentication = createAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);

// Process the authentication
if (authentication != null) {
Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal();

// Get user details from the principal
String name = principal.getName();
List emailList = principal.getAttributes().get("email");
String email = (emailList != null && !emailList.isEmpty()) ? emailList.get(0).toString() : "Email not found";

System.out.println("Authenticated User: " + name + ", Email: " + email);

return "SAML authentication successful for: " + name + ", Email: " + email;
} else {
return "Authentication failed or incorrect SAML response.";
}
}

private Saml2AuthenticationToken parseSamlResponse(String samlResponse) throws Exception {
// Spring Security automatically parses the SAML response and creates a Saml2AuthenticationToken
// The token will have the principal and authorities populated if the response is valid
Saml2AuthenticationToken token = new Saml2AuthenticationToken(repository.findByRegistrationId("microsoft"), samlResponse);

// Spring Security's internal filters should handle the population of the principal and authorities
return token;
// return OpenSamlUtils.parseResponse(samlResponse);
}

private Authentication createAuthentication(Saml2AuthenticationToken token) {
if (token == null || token.getPrincipal() == null) {
return null;
}

// Create the authentication object with the user's principal and authorities
List  authorities = token.getAuthorities().stream().toList();

return new Saml2AuthenticationToken(
(RelyingPartyRegistration) token.getPrincipal(),
(String) token.getCredentials(),
(AbstractSaml2AuthenticationRequest) authorities
);
}
}
< /code>
Hier ist meine Sicherheitskonfiguration < /p>

import org.cryptacular.io.ClassPathResource;
import org.opensaml.security.x509.X509Credential;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.saml2.provider.service.registration.*;
import org.springframework.security.web.SecurityFilterChain;

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

public static final String IDP_METADATA_URL = "my idp metadata url";

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf
.ignoringRequestMatchers("/saml/acs", "/saml/metadata", "/saml/testing") // Disable CSRF for SAML endpoints
)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/saml/testing"  ,"/saml/acs", "/saml/metadata", "/saml/metadata/**", "/error").permitAll()
.anyRequest().authenticated()
)
.saml2Login(Customizer.withDefaults())
.logout(Customizer.withDefaults());

http.cors(AbstractHttpConfigurer::disable);

return http.build();
}

@Bean
public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
RelyingPartyRegistration registration = RelyingPartyRegistrations
.fromMetadataLocation(IDP_METADATA_URL)  // Ensure this is correct
.registrationId("microsoft")
.entityId("my idp url")
.assertionConsumerServiceLocation("http://localhost:8080/saml/acs")

.assertionConsumerServiceBinding(Saml2MessageBinding.POST)
.build();

return new InMemoryRelyingPartyRegistrationRepository(registration);
}

@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class).build();
}

}

< /code>
Hier sind meine POM -Abhängigkeiten < /p>



org.springframework.boot
spring-boot-starter-security




org.springframework.boot
spring-boot-starter-web




org.springframework.boot
spring-boot-starter-test
test




org.springframework.security
spring-security-test
test



org.springframework.security
spring-security-saml2-service-provider


org.opensaml
opensaml-core
4.0.1


org.opensaml
opensaml-saml-api
4.0.1



org.opensaml
opensaml-saml-impl
4.0.1



Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post