Я сталкиваюсь с некоторыми проблемами с интеграцией моей Entra с моим приложением Spring Boot для SSO с помощью SAML. Моя среда - Spring Boot 3.4.3, Java 17. Я создал пользователя на Entra для реализации SSO, и часть входа в систему работает нормально, но когда он перенаправлен на мое приложение из URL -адреса ответа, Spring Security должна создать объект аутентификации с надлежащими значениями, где я получаю их как нулевое. Я создал индивидуальный объект аутентификации, используя SamlResponse из параметров запроса, которые я проверял через отладчик, является правильным, но SAML2AuthenticationToken при создании снова имеет нулевые значения.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>
Вот моя конфигурация безопасности < /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>
Вот мои зависимости от POM < /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
Подробнее здесь: https://stackoverflow.com/questions/795 ... pring-boot
Интеграция Microsoft Entra SSO SAML с Spring Boot ⇐ JAVA
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Spring Security SAML: принимать только подписанные ответные сообщения SAML от IDP
Anonymous » » в форуме JAVA - 0 Ответы
- 16 Просмотры
-
Последнее сообщение Anonymous
-