Expand my Community achievements bar.

Learn about Edge Delivery Services in upcoming GEM session
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