javaspringspring-bootsamlopensaml

spring-boot saml2login get relying party entity ID in AuthenticationSuccessHandler?


I have a multi-tenet application that user spring-boot saml2login (finally migrated from spring-saml extension). Two tenents can authenticate a single user (identified by an email address). Think two schools districts, grade school and high school both have a parent account (parent@gmail.com) associated for two kids they have at each building. I need to know which IDP is sending me the saml response. In the old school, spring-saml extension, I could do:

    final SAMLCredential samlCred = (SAMLCredential) (authentication.getCredentials());
    if (samlCred != null) {
        return getCustomerService().getActiveCustomerBySamlEntityId(samlCred.getRemoteEntityID())
                .filter(c -> c != null && c.isFullyActive());
    }

To get entity ID and the associated customer, but with the new saml2login in spring boot 2.5+, calling:

 authentication.getCredentials() 

just returns a string of the SAML response (XML) that I'd need to parse (and maybe decrypt). So is there an easy method to get the IPD's information, preferably the entity ID from the Authentication (or Saml2AuthenticatedPrincipal) in Spring Security?


Solution

  • Here is how I ended up doing this in case anyone else is curious:

    To get the raw xml response:

    Saml2Authentication.getSaml2Response();
    

    Pass the XML into the following utility function:

    public static Optional<String> parseIdpEntityId(String xmlResponse) {
        if ( xmlResponse == null || xmlResponse.trim().length() == 0 ) {
            log.info("Failed to parse XML SAML Response, null or empty.");
            return Optional.empty();
        }
    
        try (InputStream inputStream = new ByteArrayInputStream(xmlResponse.getBytes())) {
            Document messageDoc;
            BasicParserPool basicParserPool = new BasicParserPool();
            basicParserPool.initialize();
            messageDoc = basicParserPool.parse(inputStream);
            Element messageElem = messageDoc.getDocumentElement();
            Unmarshaller unmarshaller = XMLObjectProviderRegistrySupport.getUnmarshallerFactory().getUnmarshaller(messageElem);
            XMLObject samlObject = unmarshaller.unmarshall(messageElem);
            Response response = (Response) samlObject;
            if ( response != null && response.getIssuer() != null ) {
                return Optional.ofNullable(response.getIssuer().getValue().trim());
            }
        } catch (Exception e) {
            log.warn("Failed to parse SAML response: {}", e.getMessage(), e);
        }
    
        return Optional.empty();
    }