Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

Capturing SAML response in JAVA CODE using AEM6.5

Avatar

Level 8

Hi,

 

We are using AEM6.5 version, I would a mechanism to capture the saml response in JAVA code .

 

I would need to read data like email id , username like first and last name, other details which are part of saml response. I would want to capture in java code to do other processing checks

 

Any sample code that I could use, will be very helpful

 

Regards,

Srinivas

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Dear @srinivas_chann1 

You may refer to the below sample code here 

@Component(immediate = true, metatype = false)
@Service
public class SAMLResponsePostProcessor implements AuthenticationInfoPostProcessor {

 private static final Logger LOGGER = LoggerFactory.getLogger(SAMLResponsePostProcessor.class);

 @Reference
 private SlingSettingsService slingSettingsService; 

 public void postProcess(AuthenticationInfo info, HttpServletRequest request, HttpServletResponse response)
   throws LoginException {
  HttpServletResponse httpResponse = null;
  HttpServletRequest httpRequest = null;
  try {
   LOGGER.info("SAMLResponse Post Processor invoked");
   httpResponse = response;
   httpRequest = request;
   String pathInfo = httpRequest.getPathInfo();
   Set<String> runModes = slingSettingsService.getRunModes();
   if (runModes.contains("publish") && StringUtils.isNotEmpty(pathInfo)
     && pathInfo.contains("saml_login")) {
    LOGGER.info("SAMLResponse Post Processor processing ...");
    String responseSAMLMessage = httpRequest.getParameter("saml_login");
    if (StringUtils.isNotEmpty(responseSAMLMessage)) {
     LOGGER.debug("responseSAMLMessage:" + responseSAMLMessage);
     String base64DecodedResponse = decodeStr(responseSAMLMessage);
     LOGGER.debug("base64DecodedResponse:" + base64DecodedResponse);
     parseSAMLResponse(httpResponse, httpRequest, runModes, base64DecodedResponse);
    } else {
     LOGGER.info("responseSAMLMessage is empty or null");
    }
   }
  } catch (ParserConfigurationException e) {
   LOGGER.error("Unable to get Document Builder ", e);
  } catch (SAXException e) {
   LOGGER.error("Unable to parse the xml document ", e);
  } catch (IOException e) {
   LOGGER.error("IOException ", e);
  }
 }

 /**
  * This method will parse the SAML response to create the Cookie by reading the attributes.
  * 
  * @param httpResponse
  * @param httpRequest
  * @param runModes
  * @param base64DecodedResponse
  * @throws ParserConfigurationException
  * @throws SAXException
  * @throws IOException
  * @throws UnsupportedEncodingException
  */
 private void parseSAMLResponse(HttpServletResponse httpResponse, HttpServletRequest httpRequest,
   Set<String> runModes, String base64DecodedResponse)
   throws ParserConfigurationException, SAXException, IOException, UnsupportedEncodingException {
  DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  documentBuilderFactory.setNamespaceAware(true);
  DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
  Map<String, String> samlAttributeMap = new HashMap<String, String>();
  StringReader strReader = new StringReader(base64DecodedResponse);
  InputSource inputSource = new InputSource(strReader);
  Document document = docBuilder.parse(inputSource);
  NodeList samlAssertion = document.getElementsByTagName("saml:Assertion");
  populateSAMLAttrMap(samlAttributeMap, samlAssertion);  
 }

  /**
  * This method would populate the SAML attribute map object based on the attributes present in the response.
  * 
  * @param samlAttributeMap
  * @param samlAssertion
  */
 private void populateSAMLAttrMap(Map<String, String> samlAttributeMap, NodeList samlAssertion) {
  for (int i = 0; i < samlAssertion.getLength(); i++) {
   Node item = samlAssertion.item(i);
   NodeList childNodes = item.getChildNodes();
   for (int j = 0; j < childNodes.getLength(); j++) {
    Node subChildNode = childNodes.item(j);
    if (subChildNode.getNodeName().equalsIgnoreCase("saml:AttributeStatement")) {
     NodeList childNodes2 = subChildNode.getChildNodes();
     for (int k = 0; k < childNodes2.getLength(); k++) {
      Node item2 = childNodes2.item(k);
      if (item2.getNodeName().equalsIgnoreCase("saml:Attribute")) {
       String attributeValue = item2.getAttributes().item(0).getNodeValue();
       NodeList attributeValueNodeList = item2.getChildNodes();
       for (int l = 0; l < attributeValueNodeList.getLength(); l++) {
        if (attributeValueNodeList.item(l).getNodeName()
          .equalsIgnoreCase("saml:AttributeValue")) {
         samlAttributeMap.put(attributeValue,
           attributeValueNodeList.item(l).getTextContent());
        }
       }
      }
     }
    }
   }
  }
 }

 /**
  * This method would decode the SAML response.
  * 
  * @param encodedStr
  * @return
  */
 public static String decodeStr(
   String encodedStr) {
  String decodedXML = "";
  org.apache.commons.codec.binary.Base64 base64Decoder = new org.apache.commons.codec.binary.Base64();
  byte[] xmlBytes = encodedStr.getBytes();
  byte[] base64DecodedByteArray = base64Decoder.decode(xmlBytes);
  decodedXML = new String(base64DecodedByteArray);
  return decodedXML;
 }

}


Hope that helps!

Regards,

Santosh

View solution in original post

2 Replies

Avatar

Correct answer by
Community Advisor

Dear @srinivas_chann1 

You may refer to the below sample code here 

@Component(immediate = true, metatype = false)
@Service
public class SAMLResponsePostProcessor implements AuthenticationInfoPostProcessor {

 private static final Logger LOGGER = LoggerFactory.getLogger(SAMLResponsePostProcessor.class);

 @Reference
 private SlingSettingsService slingSettingsService; 

 public void postProcess(AuthenticationInfo info, HttpServletRequest request, HttpServletResponse response)
   throws LoginException {
  HttpServletResponse httpResponse = null;
  HttpServletRequest httpRequest = null;
  try {
   LOGGER.info("SAMLResponse Post Processor invoked");
   httpResponse = response;
   httpRequest = request;
   String pathInfo = httpRequest.getPathInfo();
   Set<String> runModes = slingSettingsService.getRunModes();
   if (runModes.contains("publish") && StringUtils.isNotEmpty(pathInfo)
     && pathInfo.contains("saml_login")) {
    LOGGER.info("SAMLResponse Post Processor processing ...");
    String responseSAMLMessage = httpRequest.getParameter("saml_login");
    if (StringUtils.isNotEmpty(responseSAMLMessage)) {
     LOGGER.debug("responseSAMLMessage:" + responseSAMLMessage);
     String base64DecodedResponse = decodeStr(responseSAMLMessage);
     LOGGER.debug("base64DecodedResponse:" + base64DecodedResponse);
     parseSAMLResponse(httpResponse, httpRequest, runModes, base64DecodedResponse);
    } else {
     LOGGER.info("responseSAMLMessage is empty or null");
    }
   }
  } catch (ParserConfigurationException e) {
   LOGGER.error("Unable to get Document Builder ", e);
  } catch (SAXException e) {
   LOGGER.error("Unable to parse the xml document ", e);
  } catch (IOException e) {
   LOGGER.error("IOException ", e);
  }
 }

 /**
  * This method will parse the SAML response to create the Cookie by reading the attributes.
  * 
  * @param httpResponse
  * @param httpRequest
  * @param runModes
  * @param base64DecodedResponse
  * @throws ParserConfigurationException
  * @throws SAXException
  * @throws IOException
  * @throws UnsupportedEncodingException
  */
 private void parseSAMLResponse(HttpServletResponse httpResponse, HttpServletRequest httpRequest,
   Set<String> runModes, String base64DecodedResponse)
   throws ParserConfigurationException, SAXException, IOException, UnsupportedEncodingException {
  DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  documentBuilderFactory.setNamespaceAware(true);
  DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
  Map<String, String> samlAttributeMap = new HashMap<String, String>();
  StringReader strReader = new StringReader(base64DecodedResponse);
  InputSource inputSource = new InputSource(strReader);
  Document document = docBuilder.parse(inputSource);
  NodeList samlAssertion = document.getElementsByTagName("saml:Assertion");
  populateSAMLAttrMap(samlAttributeMap, samlAssertion);  
 }

  /**
  * This method would populate the SAML attribute map object based on the attributes present in the response.
  * 
  * @param samlAttributeMap
  * @param samlAssertion
  */
 private void populateSAMLAttrMap(Map<String, String> samlAttributeMap, NodeList samlAssertion) {
  for (int i = 0; i < samlAssertion.getLength(); i++) {
   Node item = samlAssertion.item(i);
   NodeList childNodes = item.getChildNodes();
   for (int j = 0; j < childNodes.getLength(); j++) {
    Node subChildNode = childNodes.item(j);
    if (subChildNode.getNodeName().equalsIgnoreCase("saml:AttributeStatement")) {
     NodeList childNodes2 = subChildNode.getChildNodes();
     for (int k = 0; k < childNodes2.getLength(); k++) {
      Node item2 = childNodes2.item(k);
      if (item2.getNodeName().equalsIgnoreCase("saml:Attribute")) {
       String attributeValue = item2.getAttributes().item(0).getNodeValue();
       NodeList attributeValueNodeList = item2.getChildNodes();
       for (int l = 0; l < attributeValueNodeList.getLength(); l++) {
        if (attributeValueNodeList.item(l).getNodeName()
          .equalsIgnoreCase("saml:AttributeValue")) {
         samlAttributeMap.put(attributeValue,
           attributeValueNodeList.item(l).getTextContent());
        }
       }
      }
     }
    }
   }
  }
 }

 /**
  * This method would decode the SAML response.
  * 
  * @param encodedStr
  * @return
  */
 public static String decodeStr(
   String encodedStr) {
  String decodedXML = "";
  org.apache.commons.codec.binary.Base64 base64Decoder = new org.apache.commons.codec.binary.Base64();
  byte[] xmlBytes = encodedStr.getBytes();
  byte[] base64DecodedByteArray = base64Decoder.decode(xmlBytes);
  decodedXML = new String(base64DecodedByteArray);
  return decodedXML;
 }

}


Hope that helps!

Regards,

Santosh

Avatar

Level 8

Hi Santosh,

 

Thanks for the reply with sample code.

 

Need one more information. How will this component be invoked by saml response after login.

 

I see entries in our code base like 

com.adobe.granite.auth.saml.SamlAuthenticationHandler-app1.xml  , we have like this 4 apps,I meant app1,app2,app3,app4.

 

I also see the as soon as the user logs in it creates a Node for the user details under /home with rep:user.

 

But don't see any entries in com.adobe.granite.auth.saml.SamlAuthenticationHandler-app1.xml   for user creation under 

/home with rep:user.

 

So how is that the above sample code will be hit when we saml login happnes

 

Please provide inputs

 

Thanks,

Srinivas