import java.io.PrintWriter;
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.X509EncodedKeySpec;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.opensaml.common.binding.BasicSAMLMessageContext;
import org.opensaml.saml2.binding.decoding.HTTPPostDecoder;
import org.opensaml.ws.message.MessageContext;
import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.Attribute;
import org.opensaml.saml2.core.AttributeStatement;
import org.opensaml.saml2.core.Response;
import org.opensaml.saml2.encryption.Decrypter;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.encryption.DecryptionException;
import org.opensaml.xml.encryption.InlineEncryptedKeyResolver;
import org.opensaml.xml.security.keyinfo.StaticKeyInfoCredentialResolver;
import org.opensaml.xml.security.x509.BasicX509Credential;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureValidator;
import org.opensaml.xml.validation.ValidationException;
/**
* @author kevnls
* If you use this code as a base for your implementation please leave this comment intact.
* You should add your own name in addition.
*/
public class ProcessSAML extends HttpServlet {
/**
* Processes requests for both HTTP
GET
and POST
methods.* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
File signatureVerificationPublicKeyFile = new File("C:\\Documents and Settings\\kevnls\\My Documents\\NetBeansProjects\\SAMLReceiver\\files\\IdPSigningCert.cer");
File decryptionPrivateKeyFile = new File("C:\\Documents and Settings\\kevnls\\My Documents\\NetBeansProjects\\SAMLReceiver\\files\\SPEncryptionCert.jks");
String decryptionPrivateKeyName = "pvktmp:bd5ba0e0-9718-48ea-b6e6-32cd9c852d76";
String decryptionPrivateKeyPassword = "!c3c0ld";
try
{
//bootstrap the opensaml stuff
org.opensaml.DefaultBootstrap.bootstrap();
// get the message context
MessageContext messageContext = new BasicSAMLMessageContext();
messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(request));
HTTPPostDecoder samlMessageDecoder = new HTTPPostDecoder();
samlMessageDecoder.decode(messageContext);
// get the SAML Response
Response samlResponse = (Response)messageContext.getInboundMessage();
//get the certificate from the file
InputStream inputStream2 = new FileInputStream(signatureVerificationPublicKeyFile);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate)certificateFactory.generateCertificate(inputStream2);
inputStream2.close();
//pull out the public key part of the certificate into a KeySpec
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(certificate.getPublicKey().getEncoded());
//get KeyFactory object that creates key objects, specifying RSA
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//generate public key to validate signatures
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
//create credentials
BasicX509Credential publicCredential = new BasicX509Credential();
//add public key value
publicCredential.setPublicKey(publicKey);
//create SignatureValidator
SignatureValidator signatureValidator = new SignatureValidator(publicCredential);
//get the signature to validate from the response object
Signature signature = samlResponse.getSignature();
//try to validate
try
{
signatureValidator.validate(signature);
}
catch (ValidationException ve)
{
out.println("Signature is not valid.");
out.println(ve.getMessage());
return;
}
//no validation exception was thrown
out.println("Signature is valid.");
//start decryption of assertion
//load up a KeyStore
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(decryptionPrivateKeyFile), decryptionPrivateKeyPassword.toCharArray());
RSAPrivateKey privateKey = (RSAPrivateKey) keyStore.getKey(decryptionPrivateKeyName, decryptionPrivateKeyPassword.toCharArray());
//create the credential
BasicX509Credential decryptionCredential = new BasicX509Credential();
decryptionCredential.setPrivateKey(privateKey);
StaticKeyInfoCredentialResolver skicr = new StaticKeyInfoCredentialResolver(decryptionCredential);
//create a decrypter
Decrypter decrypter = new Decrypter(null, skicr, new InlineEncryptedKeyResolver());
//decrypt the first (and only) assertion
Assertion decryptedAssertion;
try
{
decryptedAssertion = decrypter.decrypt(samlResponse.getEncryptedAssertions().get(0));
}
catch (DecryptionException de)
{
out.println("Assertion decryption failed.");
out.println(de.getMessage());
return;
}
out.println("Assertion decryption succeeded.");
//loop through the nodes to get the Attributes
//this is where you would do something with these elements
//to tie this user with your environment
List
for (int i = 0; i < attributeStatements.size(); i++)
{
List
for (int x = 0; x < attributes.size(); x++)
{
String strAttributeName = attributes.get(x).getDOM().getAttribute("Name");
List
for (int y = 0; y < attributeValues.size(); y++)
{
String strAttributeValue = attributeValues.get(y).getDOM().getTextContent();
out.println(strAttributeName + ": " + strAttributeValue + " ");
}
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
//
/**
* Handles the HTTP
GET
method.* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP
POST
method.* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "This servlet processes a SAML 2.0 Response. It verifies the signature, " +
"decrypts an assertion, and parses out the data in the attribute statements. " +
"If you use this code as a base for your implementation please leave the @author comment intact. " +
"You should add your own name in addition.";
}//
}
1 comment:
Awesome practicla example !!
Many thanks for this blog :)
Post a Comment