Verify Saml using Java Callout

Hi,

We have a requirement where we need to use saml to authorize the api call. The saml assertion response is passed as a header value. The message content-type is non-xml. We are trying to figure out how to validate the saml as the OOB policy requires the message / request to be in xml format. Is there any java callout that we can use to validate the saml ? Any help or guidance is really appreciated.

Thanks

 

Solved Solved
0 4 297
1 ACCEPTED SOLUTION

Yes, as described in the README for that callout

The ValidateSAMLAssertion policy requires an input of type Message. This callout can emit the XML string value into either,

  • a context variable of String type
  • a context variable of Message type

The callout can create a context variable of String type. Unfortunately the callout is not able to create a variable of type Message on its own.

Therefore one way or the other, you need to create a Message, which you can do with an AssignMessage policy. You can attach the AssignMessage policy into the flow either before or after the callout runs.

So, what you must do is use AssignMessage to create a new, contrived message, just for the purposes of holding the decoded XML, the SAML assertion. Then run that decoder policy, and have it emit the decoded XML into that contrived message. Then ValidateSAMLAssertion, specifying as the source, the contrived Message.  You can name the message anything, just not "message", or "request" or "response".  

The example bundle in that code repo shows how it would work in the policy attachment: 

      <Request>
        <Step>
          <Name>AM-ContrivedMessage-1</Name>
        </Step>
        <Step>
          <Name>Java-SamlDecoder</Name>
        </Step>
        <!-- insert your ValidateSAMLAssertion policy here -->

 And then the AssignMessage looks like this: 

<AssignMessage name='AM-Holder-Message-1'>
  <!-- create a new message with a name of "holderMessage" -->
  <AssignTo createNew='true' transport='http' type='request'>holderMessage</AssignTo>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <Set>
    <!-- An empty payload. It will get filled by the subsequent step. -->
    <Payload contentType='text/plain'/>
    <Verb>POST</Verb>
  </Set>
</AssignMessage>

Then decode, 

<JavaCallout name='Java-SamlDecoder'>
  <Properties>
    <!-- 
      The header referenced here contains the compressed, then base64-encoded 
      assertion. If there is a prefix to the assertion, then you need to strip it 
      using something like ExtractVariables, and specify the variable holding
      the extracted value here.
    -->
    <Property name='input'>{message.header.assertion}</Property>
    <Property name='output'>holderMessage</Property>
  </Properties>
  <ClassName>com.google.apigee.callouts.SamlDecoder</ClassName>
  <ResourceURL>java://apigee-java-callout-samldecoder-20220110.jar</ResourceURL>
</JavaCallout>

Then ValidateSAMLAssertion specifying the holderMessage as the source.

View solution in original post

4 REPLIES 4

This callout might work for you. Check the README. 

Thanks Dino. I checked the callout. It solves one of my problems around decoding the saml response that is coming part of the header. However, i have the saml response coming in header and the message body is of type json. If i specify the "Message" as the source for ValidateSAMLAssertion policy it doesn't work as the inbound request is JSON. Is there a way to solve that issue or do i need to create a separate service which does saml verification and call that using a service callout. I am trying to prevent the service call as see if i can do the decoding and verification within the same service.

Yes, as described in the README for that callout

The ValidateSAMLAssertion policy requires an input of type Message. This callout can emit the XML string value into either,

  • a context variable of String type
  • a context variable of Message type

The callout can create a context variable of String type. Unfortunately the callout is not able to create a variable of type Message on its own.

Therefore one way or the other, you need to create a Message, which you can do with an AssignMessage policy. You can attach the AssignMessage policy into the flow either before or after the callout runs.

So, what you must do is use AssignMessage to create a new, contrived message, just for the purposes of holding the decoded XML, the SAML assertion. Then run that decoder policy, and have it emit the decoded XML into that contrived message. Then ValidateSAMLAssertion, specifying as the source, the contrived Message.  You can name the message anything, just not "message", or "request" or "response".  

The example bundle in that code repo shows how it would work in the policy attachment: 

      <Request>
        <Step>
          <Name>AM-ContrivedMessage-1</Name>
        </Step>
        <Step>
          <Name>Java-SamlDecoder</Name>
        </Step>
        <!-- insert your ValidateSAMLAssertion policy here -->

 And then the AssignMessage looks like this: 

<AssignMessage name='AM-Holder-Message-1'>
  <!-- create a new message with a name of "holderMessage" -->
  <AssignTo createNew='true' transport='http' type='request'>holderMessage</AssignTo>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <Set>
    <!-- An empty payload. It will get filled by the subsequent step. -->
    <Payload contentType='text/plain'/>
    <Verb>POST</Verb>
  </Set>
</AssignMessage>

Then decode, 

<JavaCallout name='Java-SamlDecoder'>
  <Properties>
    <!-- 
      The header referenced here contains the compressed, then base64-encoded 
      assertion. If there is a prefix to the assertion, then you need to strip it 
      using something like ExtractVariables, and specify the variable holding
      the extracted value here.
    -->
    <Property name='input'>{message.header.assertion}</Property>
    <Property name='output'>holderMessage</Property>
  </Properties>
  <ClassName>com.google.apigee.callouts.SamlDecoder</ClassName>
  <ResourceURL>java://apigee-java-callout-samldecoder-20220110.jar</ResourceURL>
</JavaCallout>

Then ValidateSAMLAssertion specifying the holderMessage as the source.

Thanks Dino