Sunday, September 25, 2011

Receiving and Processing a SAML 2.0 Response With an HttpServlet Using OpenSAML

Due to the popularity of my prior posts on processing SAML using OpenSAML I put together this code that shows a more real-world-example of how you would setup an HttpServlet to sit and listen for SAML Responses that are posted to it.  Then it just shows what you might do with the Response to get what you need out of it.  Again, I'm just verifying the Signature on the Response, Decrypting the Assertion and then looping through the Attribute nodes to look at the name/value pairs.  There are other things that you might want to do such as receiving the signing-key from the Response itself (if it's being sent), or verifying a Signature on the Assertion if that's what's being signed.  The trouble I've found with SAML implementations is that the spec is consistent, but how people use it isn't, so you'll undoubtedly need to tweak something depending on what your requirements are, but this code should get you started.

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 attributeStatements = decryptedAssertion.getAttributeStatements();
            for (int i = 0; i < attributeStatements.size(); i++)
            {
                List attributes = attributeStatements.get(i).getAttributes();
                for (int x = 0; x < attributes.size(); x++)
                {
                    String strAttributeName = attributes.get(x).getDOM().getAttribute("Name");

                    List attributeValues = attributes.get(x).getAttributeValues();
                    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.";
    }//


}



Anyway, hope this is useful to someone.

Saturday, September 24, 2011

Dark Arduino IDE Theme

I'm totally having fun playing around with my Arduino UNO, but the Arduino IDE is a little too bright for my tastes, so I created a dark theme and posted it here.

Here's a screenshot:



All you need to do is find your 'theme' folder (it may be nested a bit but it should be in the application folder somewhere under /lib/) and replace it with this folder.  I created this on a mac and it's theming version 1.0 of the IDE, but I'm guessing the theme folder is the same for all platforms.  Make a backup of yours before you drop this one in just in case though. 

You'll need to restart the Arduino IDE for the changes to take effect, but then you can sit back and let your eyes thank you!

Hope you like it.

Wednesday, June 8, 2011

Using Javascript to Manipulate DOM Elements in Hype

I’ve been having a lot of fun playing with Tumult’s recently-released tool called Hype for the Mac. It’s a time-line based tool for creating rich animated HTML5 content that runs natively in most modern browsers. We’ve been hearing for quite some time that Flash is no longer needed with all of HTML5 and CSS3’s capabilities, but no one had come up with a design-centric tool for creating that content. That’s where Hype has stepped in. For anyone familiar with working in Adobe’s Flash design tools, Hype should be fairly straightforward to work with. I had an interactive mobile site targeted at the iPhone finished in a few hours, with stuff animating into view, and custom buttons triggering animations between scenes. The problem I ran into though came when I wanted to start thinking about getting dynamic content from the outside world into the site instead of coding everything inside the Hype-generated container (most of the stuff lives in an ugly javascript file so don’t plan on working with content you’ve put into Hype after you’ve ‘compiled’ it down). That’s the one place I think it falls a little short. Although it’s nice that, unlike Flash, it exports to pure javascript/css, it’s still kind of an enclosed blob for all intents and purposes once you’ve moved out of the Hype application.

So, here’s the design I was trying to achieve. I had a home page that I wanted to populate with some dynamic content from my FriendFeed account via RSS. I decided to use Google’s javascript API for the RSS communication, and that’s pretty straightforward and well-documented on Google’s site. The problem I ran into was getting that code integrated with Hype. This is how I got it working.

Basically Hype has some event-hooks where you can trigger a javascript function. For what I was trying to achieve it made the most sense to tap into the hook that occurs after the animation for the home page has completed. I added a function called loadRSSContent and did the event-wiring in the GUI, which is trivially simple. Then I added a couple of lines of javascript to that function that would call another function that lives on the .html page that houses the Hype container. It’s not very well documented on the Hype site, but you can use any javascript functions/libraries within Hype that will eventually be available on the enclosing page at runtime. There is currently no support for importing these assets at design-time though (although that seems like an easy feature to add) so you’re flying-blind until you run the export and embed the container on a page. This is why I would suggest getting everything running on a test page and then only moving the pieces into Hype that are necessary to manipulate the DOM elements on the timeline. You’ll understand what I mean when you see the code.

So, on my home scene I added a Hype text box, and within it I created a div with id=“rssDiv”.

On the ‘On Animation Complete” event for the scene, the javascript in Hype looks like this:

function loadRSSContent(hypeDocument, element)
  //get the content for the rssDiv from a function outside of Hype
  var rssDiv = document.getElementById("rssDiv");
  rssDiv.innerHTML = getRSSContent();
}

The javascript that does the work lives on the .html page (outside of the Hype container). I should also point out what I’m doing here. I’m using the initialize() function to put the RSS html into a hidden element on the page, and then the getRSSContent() function takes that content and hands it back inside the Hype container when it requests it. The reason I’m doing it this way is because the DOM gets built dynamically with Hype, so you don’t want to try to manipulate it directly from outside of the Hype container. Also, the initialize() function can run as soon as the Google API is loaded and get the content ready while Hype is doing its animation stuff.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv=“Content-Type” content=“text/html; charset=utf-8”>
<meta http-equiv=“X-UA-Compatible” content=“chrome=1”>
<meta name=“viewport” content=“user-scalable=yes, width=320px” />
<script type=“text/javascript” src=“https://www.google.com/jsapi?key=yourkey”></script>
<script src=“https://www.google.com/uds/?file=feeds&v=1” type=“text/javascript”></script>
<script type=“text/javascript”>

function initialize() {
  var feed = new google.feeds.Feed(“http://friendfeed.com/kevnls?format=atom&num=4”);
  feed.setNumEntries(4);
  feed.load(function(result) {
    if (!result.error) {
      var html = ‘’;
      for (var i = 0; i < result.feed.entries.length; i++) {
        var entry = result.feed.entries[i];
        html += ‘<a href=“’ + entry.link + ‘” target=“_blank”>’ + entry.title + ‘</a><br/><br/>’;
      }
      document.getElementById(“hiddenElement”).value = html;
    }
  });
}

google.setOnLoadCallback(initialize);

function getRSSContent() {
  var hiddenElement = document.getElementById(“hiddenElement”);
  var rssResult = hiddenElement.value;
  return rssResult;
}
  
</script>
<title>kevnls</title>
        <style>
                body {
                        background-color: #FFFFFF;
                        margin: 0px;
                }
        </style>
</head>
<body>
        <input type=“hidden” id=“hiddenElement” value=“” />
        <div style =“margin:auto;width:320px”>  
        <!-- copy these lines to your document: -->
        <div id=“kevnls_hype_container” style=“position:relative;overflow:hidden;width:320px;height:396px;”>
                <script type=“text/javascript” src=“mobile_Resources/kevnls_hype_generated_script.js?43552”></script>
        </div>
        <!-- end copy -->
        </div>
</body>
</html>

The result of all of this can be seen here: http://kevnls.com/mobile

Hopefully this design will prove useful to someone (besides me).

Until next time.

Tuesday, April 19, 2011

Using jQuery to Disable a Link on a Specific Day of the Week

My company has a regular scheduled downtime of our messaging-bus each Sunday.  This brings down some functionality on our site, so I needed to disable the links for those resources automatically, but instead of hiding them or pointing them somewhere else, I decided it would be nice to give the user some information about what's going on right there on the page when they click on one of the disabled links.  I came up with the following piece of code which will do that for any link with class="TibcoRequired":

<!--script to disable links to Tibco-reliant tests on Sundays-->
     
<link href="/Resources/Scripts/jQuery/css/redmond/jquery-ui-1.8.1.custom.css" rel="stylesheet" type="text/css"/>
<script src="/Resources/Scripts/jQuery/js/jquery-1.4.2.min.js"></script>
<script src="/Resources/Scripts/jQuery/js/jquery-ui-1.8.1.custom.min.js"></script>

<div id="dialog" title="Dialog Title" style="display:none;"><p>This test cannot be taken on Sundays due to a regular
  scheduled downtime of the result-tracking system.</p></div>

<script type="text/javascript">
      $('.TibcoRequired').click(function () {
        var d = new Date();
        var today = d.getDay();
        if (today == 0) {
          $('#dialog').dialog({ title: 'Message' });
          return false;
        }
      });
</script>

<!--script-->

Thursday, January 13, 2011

Creating a custom Model and passing a Linq to SQL query to a View in .net MVC

Another one of my 'I was trying to do this and having no luck finding solutions' posts, so I'll post my solution and hopefully it will help someone else in the same predicament.

This time I was working on a .NET MVC project, and trying to do some reporting.  Basically it's a simple app that records users' steps-per-day.  The users are assigned to teams and I wanted to create a page that showed the ranking of the different teams each month based on their total number of steps.  As you can imagine, I had three tables.  tblTeams, tblUsers, and tblSteps.  So, my problem was, I have a model built using Linq to SQL, and it works fine if you're working with one of the objects that relates to its table.  But, in this case I just wanted to do a simple join query, with some grouping, and return that to the view to create an html table of the different teams and their totals.  So, here's how I made it work:

First off, I created a new very simple model containing the class to hold the results of the query:

namespace StepsChallenge.Models
{
    public class TeamTotalsModel
    {
        public string TeamName { get; set; }
        public string Sum { get; set; }
    }
}

Then, in my view I added a reference to this model:

Inherits="System.Web.Mvc.ViewPage<IEnumerable<StepsChallenge.Models.TeamTotalsModel>>"

OK, now we're wired-up.  On to the data.

I wrote a Linq to SQL query that looked like this in my controller and passed it into an instance of the model class:

public class HomeController : Controller
{
        public ActionResult Index()
        {
            //get monthly steps for the teams
            var allTeamsMonthlySteps = from stepRecord in homeModel.Steps
                                       join userRecord in homeModel.Users
                                       on stepRecord.EmpID equals userRecord.EmpID
                                       join teamRecord in homeModel.Teams
                                       on userRecord.TeamID equals teamRecord.TeamID
                                       where stepRecord.Date.Month == DateTime.Now.Month
                                       group stepRecord by teamRecord.TeamName into result
                                       orderby result.Key ascending
                                       select new TeamTotalsModel
                                       {  
                                          TeamName = result.Key.ToString(),
                                          Sum = result.Sum(r => r.Steps).ToString()
                                       };

            return View(allTeamsMonthlySteps);
         }
}

Then finally, back at the view I wrote something like this:

    <table>
        <tr>
            <th>
                TeamName
            </th>
            <th>
                Sum
            </th>
        </tr>

    <% foreach (var item in Model) { %>
  
        <tr>
            <td>
                <%= Html.Encode(item.TeamName) %>
            </td>
            <td>
                <%= Html.Encode(item.Sum) %>
            </td>
        </tr>
  
    <% } %>

    </table>

So, this isn't all that complicated, but the problem I was having is that every search I did on almost every piece of this pointed me back to all the Visual Studio drag-and-drop BS for working with Linq to SQL models where there's a one-to-one relationship between objects and tables.  And, I couldn't find much help at all on writing a Linq to SQL query with multiple joins, grouping, and 'where' clauses, all together, and passing it to the view.

Anyway, maybe some poor slob like me will stumble across this and find what he needs.  Until next time.