SAML 2.0 using Groovy and Spring (part 2)

In part 1, I showed you how to write a Controller and a Service which creates the AuthnRequest and sends a redirect.

I should mention that Controller is entirely derived from Spring’s MVC use of the word, but we in fact are not using it to handle or communicate with a view, just for the amazingly simple HTTP servlet like features.

Now, in part 2, we will add to the Controller and Service classes methods which make handling the incoming SAML Assertion HTTP POST cake.

Added to our SAMLController.groovy

  
@RequestMapping(value = “/sso/saml2/verifyassertion”)
def verifySamlAssertion(HttpServletResponse response, @RequestParam String SAMLResponse) {
log.debug “Incoming SAMLResponse: \n ${SAMLResponse}”

def decodedResponse = new String(SAMLResponse.decodeBase64())
log.debug “Decoded response: ${decodedResponse}”
// call our service with the decoded message
samlService.verifyAssertion(SAMLResponse: decodedResponse)

// an exception will be thrown if we don’t reach this point
response.writer.write(“success”)
}

Added to our SAMLService.groovy


  def verifyAssertion = {
String samlResponse = Param.notEmpty it, “SAMLResponse” // this is just a helper method to check incoming params

log.debug “Parsing incoming SAMLResponse ${samlResponse}”
// parse incoming response
def xml = new XmlSlurper().parseText(samlResponse)
xml.declareNamespace(samlp: “urn:oasis:names:tc:SAML:2.0:protocol”, saml: ‘urn:oasis:names:tc:SAML:2.0:assertion’,
ds: “http://www.w3.org/2000/09/xmldsig#")

// validate issuer
def issuer = xml.‘saml:Issuer’.text()
log.debug “Issuer: ${issuer}”

// validate status code is success
def statusCode = xml.‘samlp:Status’.‘samlp:StatusCode’.@Value.text()
log.debug “StatusCode: ${statusCode}”

// validate within time

// validate signature

// validate cert
def cert = xml.‘saml:Assertion’.‘ds:Signature’.‘ds:KeyInfo’.‘ds:X509Data’.‘ds:X509Certificate’.text()
log.debug “Cert: ${cert}”

// make sure request hasn’t expired from the db

// validate the original requestId
def requestId = xml.@‘InResponseTo’.text()
log.debug “Original requestId: ${requestId}”

// look up the user in our system and create a session id (ie sign them in)
def username = xml.‘saml:Assertion’.‘saml:Subject’.‘saml:NameID’.text()
log.debug “looking up the user in our system to verify that they exist and have a username matching ${username}”

log.debug “finished asserting: success” // if we reached this point, we passed the saml test
}

Pretty straightforward (if you know Groovy, Spring MVC) and better we added no extraneous jars to our project.

Published by and tagged Code using 316 words.