How to decode the SAMLResponse from IdP(Shibboleth 3)

495 views
Skip to first unread message

jinzh...@gmail.com

unread,
Mar 1, 2017, 7:20:11 AM3/1/17
to pac4j-users
Hello,

I am a beginner to pac4j and I try to use the following code to decode the SAMLResponse to get the logon username from IdP, however, I cannot get it. Does anyone know whether the code is correct?

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        String responseMessage = request.getParameter("SAMLResponse");  <=== the message is not null here

        WebContext context = new J2EContext(request, response);
        SAML2ClientConfiguration config = new SAML2ClientConfiguration("/tmp/samlKeystore.jks", 
              "pac4j-demo-passwd", "pac4j-demo-passwd", 
              "/tmp/idp-metadata.xml");
        config.setDestinationBindingType("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
        config.setServiceProviderEntityId("https://myHost:9443/");
        config.setForceAuth(true);

        SAML2Client client = new SAML2Client(config);
        client.setCallbackUrl("https://myHost:9443/saml2sp/ACS");

        final CommonProfile profile = client.getCredentials(context).getUserProfile(); <=== profile is null here

    } catch (final HttpAction e) {
        e.printStackTrace();
    }
}

I also find a class named DefaultCallbackLogic, but I don't know how to use it. Is there a sample to show its usage?

Thanks

Jérôme LELEU

unread,
Mar 1, 2017, 8:09:45 AM3/1/17
to jinzh...@gmail.com, pac4j-users
Hi,

You skipped several steps here. I advise you to read again the README of the pac4j implementation you want to use.

You need to define the security configuration of the project (SAML2ClientConfiguration + SAML2Client + Config), then protect the URL you want ("security filter") and choose the appropriate authentication mechanisms ("clients") and use a callback URL ("callback controller") to receive the callbacks from an external IdP (like for SAML).

Thanks.
Best regards,
Jérôme


--
You received this message because you are subscribed to the Google Groups "pac4j-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sheik Syed Ali

unread,
Jul 17, 2018, 8:49:39 AM7/17/18
to Pac4j users mailing list
Hi,

After the analysis of pack4j decode response, the below code works fine for me.


String encodedMessage = request.getParameter("SAMLResponse");
final byte[] decodedBytes = Base64Support.decode(encodedMessage);
final InputStream base64DecodedMessage = new ByteArrayInputStream(decodedBytes);

BasicParserPool parserPool = new BasicParserPool();
parserPool.setMaxPoolSize(100);
parserPool.setCoalescing(true);
parserPool.setIgnoreComments(true);
parserPool.setNamespaceAware(true);
parserPool.setExpandEntityReferences(false);
parserPool.setXincludeAware(false);
parserPool.setIgnoreElementContentWhitespace(true);

final Map<String, Object> builderAttributes = new HashMap<String, Object>();
parserPool.setBuilderAttributes(builderAttributes);

final Map<String, Boolean> features = new HashMap<>();
features.put("http://apache.org/xml/features/disallow-doctype-decl", Boolean.TRUE);
features.put("http://apache.org/xml/features/validation/schema/normalized-value", Boolean.FALSE);
features.put("http://javax.xml.XMLConstants/feature/secure-processing", Boolean.TRUE);
features.put("http://xml.org/sax/features/external-general-entities", Boolean.FALSE);
features.put("http://xml.org/sax/features/external-parameter-entities", Boolean.FALSE);
parserPool.setBuilderFeatures(features);
try {
parserPool.initialize();
} catch (final ComponentInitializationException e) {
throw new RuntimeException("Exception initializing parserPool", e);
}
final SAMLObject inboundMessage = (SAMLObject) XMLObjectSupport.unmarshallFromInputStream(parserPool, base64DecodedMessage);



final SAML2ClientConfiguration cfg = new SAML2ClientConfiguration("resource:samlKeystore.jks",
"pac4j-demo-passwd",
"pac4j-demo-passwd",
"resource:testshib-providers.xml");
cfg.setMaximumAuthenticationLifetime(3600);
cfg.setServiceProviderEntityId("http://localhost:8080/searchblox/saml/callback?client_name=SAML2Client");
File spMetaData = new File("sp-metadata.xml");
cfg.setServiceProviderMetadataPath(spMetaData.getAbsolutePath());
//final SAML2Client saml2Client = new SAML2Client(cfg);
//saml2Client.init();
//saml2Client.getSignatureSigningParametersProvider();

final SAML2SBClient saml2SBClient = new SAML2SBClient(cfg);
saml2SBClient.setCallbackUrl("/callbacksheik");
saml2SBClient.init();
final Response response = (Response) inboundMessage;
Decrypter decrypter = saml2SBClient.getDecrypter();
for (final EncryptedAssertion encryptedAssertion : response.getEncryptedAssertions()) {
try {
final Assertion decryptedAssertion = decrypter.decrypt(encryptedAssertion);
response.getAssertions().add(decryptedAssertion);
} catch (final DecryptionException e) {
e.printStackTrace();
}
}
//final SignatureTrustEngine engine = saml2SBClient.getSignatureTrustEngineProvider().build();
Assertion subjectAssertion = null;
for (final Assertion assertion : response.getAssertions()) {
if (!assertion.getAuthnStatements().isEmpty()) {
/*try {
validateAssertion(assertion, context, engine, decrypter);
} catch (final SAMLException e) {
logger.error("Current assertion validation failed, continue with the next one", e);
errors.add(e);
continue;
}
context.setSubjectAssertion(assertion);*/
subjectAssertion = assertion;
break;
}
}

final String sessionIndex = getSessionIndex(subjectAssertion);
final String issuerEntityId = subjectAssertion.getIssuer().getValue();
List<AuthnStatement> authnStatements = subjectAssertion.getAuthnStatements();
List<String> authnContexts = new ArrayList<String>();
for (AuthnStatement authnStatement : authnStatements) {
if(authnStatement.getAuthnContext().getAuthnContextClassRef() != null) {
authnContexts.add(authnStatement.getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef());
}
}


final List<Attribute> attributes = new ArrayList<Attribute>();
for (final AttributeStatement attributeStatement : subjectAssertion.getAttributeStatements()) {
for (final Attribute attribute : attributeStatement.getAttributes()) {
attributes.add(attribute);
}
if (!attributeStatement.getEncryptedAttributes().isEmpty()) {
if (decrypter == null) {
System.out.println("Encrypted attributes returned, but no keystore was provided.");
} else {
for (final EncryptedAttribute encryptedAttribute : attributeStatement.getEncryptedAttributes()) {
try {
attributes.add(decrypter.decrypt(encryptedAttribute));
} catch (final DecryptionException e) {
e.printStackTrace();
}
}
}
}
}

Map<String,List<String>> testSaml = new HashMap<>();
for (final Attribute attribute : attributes) {

final String name = attribute.getName();
final String friendlyName = attribute.getFriendlyName();

final List<String> values = new ArrayList<>();
for (final XMLObject attributeValue : attribute.getAttributeValues()) {
final Element attributeValueElement = attributeValue.getDOM();
if (attributeValueElement != null) {
final String value = attributeValueElement.getTextContent();
values.add(value);
} else {
System.out.println("Attribute value DOM element is null for {}"+ attribute);
}
}
testSaml.put(friendlyName,values);
}
System.out.println("Final SAML Value:"+testSaml);


 You can just extend the SAML2Client and create the SAML2SBClient

public class SAML2SBClient extends SAML2Client{


public SAML2SBClient(SAML2ClientConfiguration clientConfiguration){
super(clientConfiguration);
}

public Decrypter getDecrypter(){
return decrypter;
}
}

Note: Only for learning purpose not for production usage because i skipped many validation.
Reply all
Reply to author
Forward
0 new messages