Overview

Single Sign-On (SSO) removes the need to repeatedly type usernames and passwords, which increases productivity and prevents many types of online fraud that is caused by using same or similar passwords across apps, tying in passwords in un-safe environments, password sharing etc.

Pre-requisites

  • You need to create a free trial account with miniOrange.
  • You should have an account of application where you want to single sign on into.

Steps to integrate miniOrange Single Sign on API for SAML

Step 1: Create a SAML request and send it to miniOrange SSO service

You need to create SAML request and send it as a GET parameter : Contact Us for url

Sample SAML request XML

        <?xml version="1.0" encoding="UTF-8"?>
        <samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
        ID="dfqeyfbencoiwejdwomwe" Version="2.0"
        IssueInstant="2014-07-07T12:06:15.889Z"
        ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
        AssertionConsumerServiceURL="https://yourdomain.com/samlresponse">
        <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
        https://yourdomain.com
        </saml:Issuer>
        </samlp:AuthnRequest>

You can use OpenSAML open source library to create this request.

Maven dependency for OpenSAML

      <dependency>
      <groupId>org.opensaml</groupId>
      <artifactId>opensaml</artifactId>
      <version>2.6.1</version>
      </dependency>

Or you can download OpenSAML open source library JAR from:

https://central.maven.org/maven2/org/opensaml/opensaml/2.6.1/opensaml-2.6.1.jar

Sample Java Code for creating the SAML request using OpenSAML library

        import java.io.ByteArrayOutputStream;
        import java.io.StringWriter;
        import java.net.URLEncoder;
        import java.util.zip.DeflaterOutputStream;

        import javax.xml.transform.Transformer;
        import javax.xml.transform.TransformerFactory;
        import javax.xml.transform.dom.DOMSource;
        import javax.xml.transform.stream.StreamResult;

        import org.apache.commons.codec.binary.Base64;
        import org.opensaml.Configuration;
        import org.opensaml.DefaultBootstrap;
        import org.opensaml.common.SAMLObjectBuilder;
        import org.opensaml.common.SAMLVersion;
        import org.opensaml.saml2.core.AuthnRequest;
        import org.opensaml.saml2.core.Issuer;
        import org.opensaml.xml.XMLObject;
        import org.opensaml.xml.io.Marshaller;
        import org.opensaml.xml.io.MarshallerFactory;
        import org.w3c.dom.Element;

        public String generateSAMLRequest() {

        DefaultBootstrap.bootstrap();
        AuthnRequest request = ((SAMLObjectBuilder) 
        Configuration.getBuilderFactory().getBuilder(
        uthnRequest.DEFAULT_ELEMENT_NAME)).buildObject();

        /* Your consumer URL (where you want to receive SAML response) */
        request.setAssertionConsumerServiceURL("https://yourdomain.com/samlresponse");

        /* Unique request ID */
        request.setID("reg-123");
        request.setVersion(SAMLVersion.VERSION_20);
        request.setIssueInstant(new org.joda.time.DateTime());
        request.setProtocolBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");

        /* Your issuer URL */
        request.setIssuer(buildIssuer("https://yourdomain.com"));

        /* Setting jsonRequestString as StringEntity */
        String base64EncodedRequest = base64EncodeXMLObject(request);
        return base64EncodedRequest;
        }

        private Issuer buildIssuer(String issuerValue) {
        Issuer issuer = ((SAMLObjectBuilder) Configuration.getBuilderFactory().getBuilder(
              Issuer.DEFAULT_ELEMENT_NAME)).buildObject();
        issuer.setValue(issuerValue);
        return issuer;
        }

        private Issuer base64EncodeXMLObject(XMLObject xmlObject) {
        MarshallerFactory marshallerFactory = Configuration.getMarshallerFactory();
        Marshaller marshaller = marshallerFactory.getMarshaller(xmlObject);
        Element samlObjectElement = marshaller.marshall(xmlObject);

        // Transforming Element into String
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        StreamResult result = new StreamResult(new StringWriter());
        DOMSource source = new DOMSource(samlObjectElement);
        transformer.transform(source, result);
        String xmlString = result.getWriter().toString();

        /* first DEFLATE compress the document (saml-bindings-2.0, section 3.4.4.1) */
        byte[] xmlBytes = xmlString.getBytes("UTF-8");
        ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
        DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(byteOutputStream);
        deflaterOutputStream.write(xmlBytes, 0, xmlBytes.length);
        deflaterOutputStream.close();

        // next, base64 encode it
        Base64 base64Encoder = new Base64();
        byte[] base64EncodedByteArray =
        base64Encoder.encode(byteOutputStream.toByteArray());
        String base64EncodedMessage = new String(base64EncodedByteArray);

        // finally, URL encode it
        String urlEncodedMessage = URLEncoder.encode(base64EncodedMessage, "UTF-8");
        return urlEncodedMessage;

Submit this request to miniOrange SSO Service


        <html>
            <head>
                <script>
                    window.onload = function() {
                          document.forms['saml-form'].submit();
                    }
                </script>
            </head>

            <form id="saml-form" method="get" action="[identity_provider_url]">

                <input type="hidden" name="SAMLRequest" value="generated-request" />

                <input type="hidden" name="RelayState" value="" />

            </form>
        </html>

Step 2: Receiving SAML response and validating signature

After successful login you will receive the SAML response containing username and signature. The username is contained in the NameIdentifier element of the Subject statement.

NOTE: It is recommended that you verify our signature before signing in the user to your application.

Sample Java Code for reading SAML Response

        import java.io.BufferedInputStream;
        import java.io.ByteArrayInputStream;
        import java.io.FileInputStream;
        import java.security.cert.CertificateFactory;
        import java.security.cert.X509Certificate;

        import javax.xml.parsers.DocumentBuilder;
        import javax.xml.parsers.DocumentBuilderFactory;

        import org.apache.commons.codec.binary.Base64;
        import org.opensaml.Configuration;
        import org.opensaml.DefaultBootstrap;
        import org.opensaml.saml2.core.Response;
        import org.opensaml.saml2.core.Subject;
        import org.opensaml.security.SAMLSignatureProfileValidator;
        import org.opensaml.xml.XMLObject;
        import org.opensaml.xml.io.Unmarshaller;
        import org.opensaml.xml.io.UnmarshallerFactory;
        import org.opensaml.xml.security.credential.Credential;
        import org.opensaml.xml.security.x509.BasicX509Credential;
        import org.opensaml.xml.signature.SignatureValidator;
        import org.w3c.dom.Document;
        import org.w3c.dom.Element;


        public String receiveSAMLResponse() {

        /* Getting the response string from HTTP Request object */
        String responseString = (String) httpRequest.getParameter("SAMLResponse");

        /* Decoding Base64 response string to get the XML string */
        String responseXml = new String(Base64.decodeBase64(responseString), "UTF-8");

        /* Generating SAML Response object from XML string */
        DefaultBootstrap.bootstrap();
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setNamespaceAware(true);
        DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
        ByteArrayInputStream is = new ByteArrayInputStream(responseXml.getBytes());
        Document document = docBuilder.parse(is);
        Element element = document.getDocumentElement();

        UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();

        Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(element);

        XMLObject xmlObj = unmarshaller.unmarshall(element);
        Response response = (Response) xmlObj;

        /* Validating the signature on the response */
        validateSignature(response);

        /* If validation was successful, get the username from the response. */
        Subject subject = response.getAssertions().get(0).getSubject();
        String username = subject.getNameID().getValue();
        return username;
        }

        private void validateSignature(Response response) {
        SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
        try {
            profileValidator.validate(response.getSignature());
        } catch (ValidationException e) {
            /* Indicates signature did not conform to SAML Signature profile */
            e.printStackTrace();
        throw e;
        }

        Credential verificationCredential = getVerificationCredential();
        SignatureValidator sigValidator = new
         SignatureValidator(verificationCredential);
        try {
            sigValidator.validate(response.getSignature());
        } catch (ValidationException e) {
            /* Indicates signature was not cryptographically valid, or possibly a processing error. */
            e.printStackTrace();
            throw e;
        }
        }

        private Credential getVerificationCredential() {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("/pathToYourCertificte"));
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            X509Certificate cert = (X509Certificate)cf.generateCertificate(bis);
            BasicX509Credential x509Credential = new BasicX509Credential();
            x509Credential.setPublicKey(cert.getPublicKey());
            x509Credential.setEntityCertificate(cert);
            Credential credential = x509Credential;
            return credential;
        }