Thursday, April 26, 2012

Unit Testing JavaScript Using Js-Test-Driver

Javascript can be easy to unit test and there are several unit test frameworks that allow this to happen.  Js-test-driver is an easy to use and actively developed framework that is fairly easy to learn and integrates well with Eclipse.

During a recent BSides conference the topic of cross server scripting (XSS) with JQuery was discussed.  This topic piqued some interest because I was interested in automating unit testing scenarios in JavaScript.  What I found was that it was easy to build JS unit tests using JS-Test-Driver test cases around JQuery to test XSS. Here's an example of a JS-test-driver test case:

/**
 * appendTest - Unit test for XSS vulnerabilities
 *
 * Copyright (C) 2012 @rcastellow
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see  *
 */

appendTest = TestCase("appendTest");

appendTest.prototype.name = "append()";

appendTest.prototype.setUp = function() {
    this.testUtils = new TestUtils();
};

appendTest.prototype.testXSS = function() {
    /*:DOC htmlTest = <div class="page"><div id="testDiv">abc</div> </div>"
     */

    var child = this.testUtils.findFirstChildByTagName(this.htmlTest, 'DIV');
    assertNotNull(child);
    assertEquals("DIV", child.tagName);

    // Add Sample XSS
    var xssElement = $(child).append("<script id='bad' src='http://badStuff.js' />");
    assertEquals('
<div id="testDiv">abc</div>', xssElement.html().trim());
  
    xssElement = $(child).append("
<h1 id='bad' >abc</h1>");
    assertEquals('
<div id="testDiv">abc</div> <h1 id="bad">abc</h1>', xssElement.html().trim());
  
  
    // 3. Test if XSS modified and made the script part of the DOM
    if (xssElement.html().trim() != '
<div id="testDiv">abc</div>') {
        jstestdriver.console.log("jQueryXSS", this.name + " has successfully modified the DOM.");
    }
};





The results of my unit tests showed me that JQuery is indeed handling some of the more common forms of XSS in more recent versions of JQuery (1.6.2+).  jQuery looks for a '<' in its parameters because it is not very common start of a parameter in Javascript, but is very common in html.  


The code that handles XSS can be found in the jQuery library in the following lines of code:


	// A simple way to check for HTML strings or ID strings
	// Prioritize #id over  to avoid XSS via location.hash (#9521)
	quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
  

Will it stop all forms of XSS? Probably not, since there are so many ways besides adding a straight html script entry into a jQuery parameter. A future exercise might be to extend my tests to include a wider variety of XSS vectors, many of which can be found here.

Thursday, April 12, 2012

Development Security Notes on Distributed Authentication

Into the Wild - Authenticate and Prevail on the Open Web
For anyone who wants to take a trip over to the east coast this weekend (4/14/2012), here's the perfect reason.  BSides (#BsidesCHS) Charleston will offer several security related presentations.  Tickets are available here.     

These notes are for the security development section of the conference.  This topic discusses distributed authentication and how to use the power of OAuth, SAML 2.0, and OpenId to simplify authentication and help bring in more end users into your site.  There is so much to cover, so this topic is by no means comprehensive, but a good primer for these topics.  I hope to see you there!


Title: Into the Wild - Authenticate and Prevail on the Open Web
Length: 50 mins
Abstract: Facebook, Twitter, Google Apps, SalesForce, Cisco, Intuit, and many apps have been using decentralized services to exchange authentication and authorization information across the web.  Learn how to integrate authentication services into your application so that you can sign in once and navigate smoothly across other trusted domains.  This presentation is hands-on and will include code (and lot's of it!) to communicate using SAML 2.0,
 OpenID, OAuth, and more.
Goals:
  1. Talk about the idea of distributed authentication
  2. Define what’s out there in the world of federated authentication.
  3. Talk about when to use certain authentication methods.
  4. Drill into the details of some of the authentication methods and how each works.
  5. Break out the code OpenID , OAuth, SAML 2.0 (Apache, PHP, Ruby, Java/Grails, Spring)

Decentralized Authentication

A Few Qualities of A Decentralized Authentication System

1.) The application is stateless with regards to managing user identities.  The application has no need for user names or passwords.  Authentication is decoupled from the application code.
2.) A session stores enough information for the client to authenticate and authorize into an application.  Allows single sign on across multiple applications.
3.) Open standards.
4.) Scalable

Terminology:

Service Providers - These are the services that are requesting that your ID is authenticated.  This is usually coupled alongside the client application.
Identity Providers - The DMV of the distributed authentication world.  This is where the identities are stored and depending on the method this is the source of trust for any requesting users attempting to authenticate.
Federated: When 2 or more identity providers have agreed to accept and/or provide themselves as authentication services.
Assertions - The license passed back from the Identity Providers back to the Service Providers who decide to accept or deny the authenticating user.
n-Legged - The number of parties involved during an OAuth authentication.
Relying party (RP) - The site that wants to verify the end-user's identifier.

Where Does this Idea of Decentralized Authentication Come From?

Decentralized authentication is not a new model.  Think of your friendly neighborhood DMV!
  1. Your state DMV issued identification cards to drive a car.  In order to receive a driver’s license you must present valid information that you are a qualified to drive and you are indeed the person that is being issued a driver’s license. (You request your credentials to be entered into the identity provider)
  2. Your are issued an identification card, and are qualified to drive in your state.  (The identity provider has your credentials)
  3. You drive into the next state Georgia.  Georgia has agreed with South Carolina to accept the premise that anyone issued a South Carolina driver’s license is qualified to drive in Georgia.  Actually, South Carolina licenses are good in all 50 states. (The DMVs are federated!)
  4. You request the privilege of visiting Bob’s BierGarten across the state line.  They check your ID and accept your are authentic based on your issued South Carolina driver’s license.  (A service provider requests valid credentials in order to provide a service.)
  5. You enjoy a tasty beverage! (You enjoy your service provided!)

Whats Out There???

There are many available services, but for the focus of this discussion, we’ll focus on the following
OpenID - openid.net - An open standard to allow users to authenticate in a decentralized manner.
SAML 2.0 - http://shibboleth.internet2.edu/ A federated authentication protocol.
OAuth - oauth.net - Created from the need to allow dashboard widgets to authenticate with their services.
Liberty Alliance - http://www.openliberty.org/ - A group of open source projects to address different concerns in web security.

Implementation Details

OAuth

OAuth is a distributed authentication open standard that allows users to share username/password tokens versus credentials and has the following benefits
  1. Allows access delegation, similar to valet keys in luxury cars you can share only specific items.  photos, files, etc
  2. Easy to use.  You use your twitter/Netflix/Google account to authenticate
  3. Saves time and money.  Sites can implement OAuth vs. building their own authentication system.
  4. Lowers the barrier of entry into a single website.
Added in many IdPs to reduce phishing: Pre-registration of the redirection URI

OpenID

OpenID is a distributed authentication open standard that allows users to share username/password tokens versus credentials and has the following benefits
  1. Allows access via an Identity Provider
  2. Easy to use.  You use your twitter/Netflix/Google account to authenticate
  3. Saves time and money.  Sites can implement OAuth vs. building their own authentication system.
  4. Lowers the barrier of entry into a single website.
Phishing - OpenID attempts to manage phishing by forcing the end user to be authenticated with the identity provider before the relying party authenticates.  In general you will probably be able to validate the identity provider and verify the certificate via ssl and will be authenticating via the IdP vs. a relying party site.

SAML 2.0

SAML 2.0 has been originated and defined by the OASIS organization and is an XML-based protocol which provides secure tokens via assertions which contain attributes about the end user that is attempting authentication.
The following protocols are supported in SAML 2.0..
  1. Assertion Query and Request Protocol (What is the attribute of account?)
  2. Authentication Request Protocol (SP requests an authentication)
  3. Artifact Resolution Protocol (A reference to a SAML message is an artifact)
  4. Name Identifier Management Protocol (A protocol which allows change to the value or format of the name of a Principal)
  5. Single Logout Protocol (A URL that allows the user to invalidate their session)
  6. Name Identifier Mapping Protocol
Bindings Supported:
  1. SAML SOAP Binding (based on SOAP 1.1)
  2. Reverse SOAP (PAOS) Binding
  3. HTTP Redirect Binding
  4. HTTP POST Binding
  5. HTTP Artifact Binding
  6. SAML URI Binding
The following profiles are supported in SAML 2.0
  1. SSO Profiles
  1. Web Browser SSO Profile  <<-- Typical use case (SP Post Request;IdP Post Response) && (SP Redirect Artifact; IdP Redirect Artifact)
  2. Enhanced Client or Proxy (ECP) Profile
  3. Identity Provider Discovery Profile
  4. Single Logout Profile
  5. Name Identifier Management Profile
  1. Artifact Resolution Profile
  2. Assertion Query/Request Profile
  3. Name Identifier Mapping Profile
  4. SAML Attribute Profiles (This is how attributes are queried)
  1. Basic Attribute Profile - name / value pairs
  2. X.500/LDAP Attribute Profile - Support for X.500 attributes
  3. UUID Attribute Profile - UUIDs can be attribute names
  4. DCE PAC Attribute Profile
  5. XACML Attribute Profile - Formatted to be processed by XACML (eXtensible Control Markup Language)

What is in an assertion?

  1. unique identifier of the IdP
  2. A digital signature of the <saml:Assertion> element
  3. An opaque transient identifier of the authenticated principal
  4. The conditions that an assertion will be valid
  5. Authentication information from the IdP
  6. An element containing information regarding the attributes released from the IdP after authentication.

Example Assertion:

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
    Destination="https://musc.sample.com/saml/SSOAssert.aspx" ID="_3f8bc264hdfghfgjhba4548c8e468f54"
    InResponseTo="_83ee9gsdfgdfgb-9cbf-42ffad75cb0b" IssueInstant="2012-04-06T18:13:53.300Z"
    Version="2.0">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
            Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://musc.sample.com/shibboleth-sp</saml2:Issuer>
    <saml2p:Status>
            <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
    </saml2p:Status>
    <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
            ID="_577663bbdsfgsdfg5e7017598c4d" IssueInstant="2012-04-06T18:13:53.300Z"
            Version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://musc.sample.com/shibboleth-sp
            </saml2:Issuer>
            <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <ds:SignedInfo>
                            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
                            <ds:Reference URI="#_5776sdfgdsfgsf7598c4d">
                                    <ds:Transforms>
                                            <ds:Transform
                                                    Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                                                    <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"
                                                            PrefixList="xs" />
                                            </ds:Transform>
                                    </ds:Transforms>
                                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                                    <ds:DigestValue>XA0sdfgdsfg4UalAe8E=</ds:DigestValue>
                            </ds:Reference>
                    </ds:SignedInfo>
                    <ds:SignatureValue>
                    </ds:SignatureValue>
                    <ds:KeyInfo>
                            <ds:X509Data>
                                    <ds:X509Certificate>
<!-- Cert goes Here -->                                    </ds:X509Certificate>
                            </ds:X509Data>
                    </ds:KeyInfo>
            </ds:Signature>
            <saml2:Subject>
                    <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
                            NameQualifier="https://musc.sample.com/shibboleth-sp"
                            SPNameQualifier="https://musc.sample.com/shibboleth-sp">_d1fa6adsffsdafadf68e87</saml2:NameID>
                    <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                            <saml2:SubjectConfirmationData
                                    Address="128.23.43.89" InResponseTo="_83ee90bfadsfasdfasdfffad75cb0b"
                                    NotOnOrAfter="2012-04-06T18:18:53.300Z" Recipient="https://musc.sample.com/saml/SSOAssert.aspx" />
                    </saml2:SubjectConfirmation>
            </saml2:Subject>
            <saml2:Conditions NotBefore="2012-04-06T18:13:53.300Z"
                    NotOnOrAfter="2012-04-06T18:18:53.300Z">
                    <saml2:AudienceRestriction>
                            <saml2:Audience>https://musc.sample.com/shibboleth-sp
                            </saml2:Audience>
                    </saml2:AudienceRestriction>
            </saml2:Conditions>
            <saml2:AuthnStatement AuthnInstant="2012-04-06T18:13:53.224Z"
                    SessionIndex="321f70424b6bd6bbcasdfadsfsdf2cab248060b3">
                    <saml2:SubjectLocality Address="128.23.43.89" />
                    <saml2:AuthnContext>
                            <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
                            </saml2:AuthnContextClassRef>
                    </saml2:AuthnContext>
            </saml2:AuthnStatement>
            <saml2:AttributeStatement>
                    <saml2:Attribute FriendlyName="uid"
                            Name="urn:oid:0.9.2342.19200300.100.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
                            <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                    xsi:type="xs:string">rob</saml2:AttributeValue>
                    </saml2:Attribute>
                    <saml2:Attribute FriendlyName="sn" Name="urn:oid:2.5.4.4"
                            NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
                            <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                    xsi:type="xs:string">Castellow</saml2:AttributeValue>
                    </saml2:Attribute>
                    <saml2:Attribute FriendlyName="entryDN" Name="urn:oid:1.3.6.1.1.20"
                            NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
                            <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                    xsi:type="xs:string">uid=robC,ou=people,dc=blaco,dc=edu</saml2:AttributeValue>
                    </saml2:Attribute>
                    <saml2:Attribute FriendlyName="mail"
                            Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
                            <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                    xsi:type="xs:string">rob@blah.edu</saml2:AttributeValue>
                    </saml2:Attribute>
            </saml2:AttributeStatement>
    </saml2:Assertion>
</saml2p:Response>

SP POST Request; IdP POST Response

Source: Wikipedia.org (Tom Scavo)

SP Redirect Artifact; IdP Redirect Artifact



Source: Wikipedia.org (Tom Scavo)

Which Method Do I Use?

SAML 2.0 - You may want to use SAML 2.0 because:

  1. You have an explicit pre-defined relationship between your relying party and the identity provider (The relationships are extremely formal)
  2. You have a pre-defined list of identity providers that are federated.  Company A wants to accept accounts from company B, so they federate their identity providers.

OpenID 2.0 - You may want to use OpenID 2.0 because:

  1. OpenID is not as formally bound to its Identity Providers, and provide more flexibility in authenticating on the web.  A service provider can be created quickly and without needing to define a relationship with IdPs in advance.
  2. No federation between IdPs.
  3. You want to make it easier for users with Google email, Yahoo, etc to authenticate to  your site

OAuth - You may want to use OAuth because:

  1. You may want to allow Twitter, Facebook, etc users to authenticate and allow service providers to have limited access to user data, files, etc.
  2. Millions of Facebook and Twitter users can use your site.
  3. It is possible to access more data from OAuth apps without asking users to fill out registration forms.

Examples



SAML 2.0 (Shibboleth) -  SP Post Request - IDP Post Response, Read Attributes from Response

Perl

#!/usr/bin/perl
use Data::Dumper;
use CGI::Cookie
print "Content-Type: text/html\n\n";
print "";
%cookies = fetch CGI::Cookie;
foreach (keys %cookies) {
            $cookie = $cookies{$_};
            print $cookie->name . " = ";
            print $cookie->value . "; ";
            print $cookie->path . "; ";
            print $cookie->expires ."
";
}
print << "-OUT-";

-OUT-
print "\n";
foreach $key (sort keys(%ENV)) {
        print "$key = $ENV{$key}
";
}
print "";

 




OpenId -  Create an OpenID, Login with OpenId, Enable your Site with OpenId




Create an OpenId


You may already have an OpenId if you use any of these services:
  1. Google
  2. Yahoo
  3. Blogspot
  4. Flickr
  5. MySpace
  6. Wordpress
  7. Chi.mp
  8. Facebook (? They are not a provider, but a supporter which means you can login with your OpenId but you cannot login to other sites with your Facebook Id.  Facebook uses Facebook Connect)


What would I see if an application supports OpenId?

Here is how you would login with your OpenId



What would be the benefits of using OpenId?


  1. Lower the barrier of entry to register at your site.  More conversions!
  2. More user information is available because the user has provided it already 1x and you are not asking them to do something that they may have already provided.
  3. Forget about providing password recovery services
  4. Allow users to publish information to other contacts or social media.

How do I enable OpenId on my website?


If you are using one of the following applications, the work has already been done for you via plugins:
  1. Drupal
  2. WordPress (OpenID)
  3. WordPress (Janrain Engage)
  4. SPIP
  5. WebGUI
  6. MediaWiki
  7. DokuWiki
  8. phpBB
  9. PunBB




Example:
 

You could also use a 3rd party hosted software to manage OpenId on your website.  Janrain Engage is one example.

Code It With Existing Libraries!
Apache 2
mod_auth_openid   Using a the openid module in Apache would be used for authenticating users attempting to enter a URI within the Apach instance.
First, load the module in Apache.
# note that the path to your module might be different
LoadModule authopenid_module /usr/lib/apache2/modules/mod_auth_openid.so
Next, configure what resources are protected and specify the IdP.
Add the following to the htttpd.conf or .htaccess file.
AuthType                          OpenID
require valid-user
The following should be added to the httpd.conf:
AuthOpenIDDBLocation              /some/location/my_file.db
AuthOpenIDTrusted                 ^http://myopenid.com/server$ ^http://someprovider.com/idp$
AuthOpenIDDistrusted              ^http://hackerdomain ^http://openid.microsoft.com$
AuthOpenIDUseCookie               Off
AuthOpenIDTrustRoot               http://example.com
AuthOpenIDCookieName              example_cookie_name
AuthOpenIDLoginPage               /login.html
AuthOpenIDCookieLifespan          3600 # one hour
AuthOpenIDServerName              http://example.com
AuthOpenIDUserProgram             /path/to/authorization/program
AuthOpenIDCookiePath              /path/to/protect
Java (See Example)
There are several Java implementations, but in this case, we’ll use JOpenId which we can find here.
Download the JOpenId library.
PHP (See Example)
OpenId Enabled library is being used to handle OpenId.
Ruby
Like our PHP implementation Open Enabled can be used with Ruby as well.
 gem install ruby-openid

Check the installation:
   $ irb
 irb> require 'rubygems'
 irb> require_gem 'ruby-openid'
 => true
require 'pathname'
require "openid"
require 'openid/extensions/sreg'
require 'openid/extensions/pape'
require 'openid/store/filesystem'
class ConsumerController < ApplicationController
  layout nil
  def index
    # render an openid form
  end
  def start
    begin
      identifier = params[:openid_identifier]
      if identifier.nil?
        flash[:error] = "Enter an OpenID identifier"
        redirect_to :action => 'index'
        return
      end
      oidreq = consumer.begin(identifier)
    rescue OpenID::OpenIDError => e
      flash[:error] = "Discovery failed for #{identifier}: #{e}"
      redirect_to :action => 'index'
      return
    end
    if params[:use_sreg]
      sregreq = OpenID::SReg::Request.new
      # required fields
      sregreq.request_fields(['email','nickname'], true)
      # optional fields
      sregreq.request_fields(['dob', 'fullname'], false)
      oidreq.add_extension(sregreq)
      oidreq.return_to_args['did_sreg'] = 'y'
    end
    if params[:use_pape]
      papereq = OpenID::PAPE::Request.new
      papereq.add_policy_uri(OpenID::PAPE::AUTH_PHISHING_RESISTANT)
      papereq.max_auth_age = 2*60*60
      oidreq.add_extension(papereq)
      oidreq.return_to_args['did_pape'] = 'y'
    end
    if params[:force_post]
      oidreq.return_to_args['force_post']='x'*2048
    end
    return_to = url_for :action => 'complete', :only_path => false
    realm = url_for :action => 'index', :id => nil, :only_path => false
   
    if oidreq.send_redirect?(realm, return_to, params[:immediate])
      redirect_to oidreq.redirect_url(realm, return_to, params[:immediate])
    else
      render :text => oidreq.html_markup(realm, return_to, params[:immediate], {'id' => 'openid_form'})
    end
  end
  def complete
    # FIXME - url_for some action is not necessarily the current URL.
    current_url = url_for(:action => 'complete', :only_path => false)
    parameters = params.reject{|k,v|request.path_parameters[k]}
    oidresp = consumer.complete(parameters, current_url)
    case oidresp.status
    when OpenID::Consumer::FAILURE
      if oidresp.display_identifier
        flash[:error] = ("Verification of #{oidresp.display_identifier}"\
                         " failed: #{oidresp.message}")
      else
        flash[:error] = "Verification failed: #{oidresp.message}"
      end
    when OpenID::Consumer::SUCCESS
      flash[:success] = ("Verification of #{oidresp.display_identifier}"\
                         " succeeded.")
      if params[:did_sreg]
        sreg_resp = OpenID::SReg::Response.from_success_response(oidresp)
        sreg_message = "Simple Registration data was requested"
        if sreg_resp.empty?
          sreg_message << ", but none was returned."
        else
          sreg_message << ". The following data were sent:"
          sreg_resp.data.each {|k,v|
            sreg_message << "<br/><b>#{k}</b>: #{v}"
          }
        end
        flash[:sreg_results] = sreg_message
      end
      if params[:did_pape]
        pape_resp = OpenID::PAPE::Response.from_success_response(oidresp)
        pape_message = "A phishing resistant authentication method was requested"
        if pape_resp.auth_policies.member? OpenID::PAPE::AUTH_PHISHING_RESISTANT
          pape_message << ", and the server reported one."
        else
          pape_message << ", but the server did not report one."
        end
        if pape_resp.auth_time
          pape_message << "<br><b>Authentication time:</b> #{pape_resp.auth_time} seconds"
        end
        if pape_resp.nist_auth_level
          pape_message << "<br><b>NIST Auth Level:</b> #{pape_resp.nist_auth_level}"
        end
        flash[:pape_results] = pape_message
      end
    when OpenID::Consumer::SETUP_NEEDED
      flash[:alert] = "Immediate request failed - Setup Needed"
    when OpenID::Consumer::CANCEL
      flash[:alert] = "OpenID transaction cancelled."
    else
    end
    redirect_to :action => 'index'
  end
  private
  def consumer
    if @consumer.nil?
      dir = Pathname.new(RAILS_ROOT).join('db').join('cstore')
      store = OpenID::Store::Filesystem.new(dir)
      @consumer = OpenID::Consumer.new(session, store)
    end
    return @consumer
  end
end

How do I become an OpenId provider? (from easiest to most difficult)

  1. Use JanRain’s software as a service (or some other service) to create an OpenId federated provider.
  2. Host an implementation yourself using existing libraries. http://openid.net/developers/libraries
  3. Develop your own customized implementations embedded in your application.


OAuth

JavaScript (Facebook)

Facebook uses OAuth 2.0 for authentication and authorization.  Here are the steps to implement authentication using OAuth in Facebook.
  1. Download the open source JavaScript SDK
  2. register your website with Facebook to get an App ID (or appId)
  3. Load the Javascript in your HTML
  1. Provide a Login for your user
  2. The user logs into the site and releases some basic information. By default, Facebook will give you access to the user's name, picture and any other data they have shared with everyone on Facebook
You can request additional attributes as well.  If the attributes are in addition to the standard attribute list, Facebook will ask the user if they would like to allow the additional attributes to be released before authentication occurs.

<html>
<head>
<title>My Facebook Login Page</title>
</head>
<!--  More information about the Facebook API can be found at http://developers.facebook.com/docs/guides/web/ -->
<!--  To undo the settings you need to go to Facebook Privacy > Apps and Websites to Revoke Authorization -->
<body>
    <div id="fb-root"></div>
    <script src="js/jquery.min.js" type="text/javascript"></script>
    <script>
           window.fbAsyncInit = function() {
             FB.init({
               appId          : '385811328105986',
               status         : true,
               cookie         : true,
               xfbml          : true,
               oauth          : true,
             });
           };
           (function(d){
              var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
              js = d.createElement('script'); js.id = id; js.async = true;
              js.src = "http://connect.facebook.net/en_US/all.js";
              d.getElementsByTagName('head')[0].appendChild(js);
             
            }(document));
           $(document).ready(function() {
               $('span#refreshStatus').on('click', function(event) {
                       event.preventDefault();
                       refreshStatus(FB);
                       userInfo(FB);
                });      
           })
           
           function refreshStatus(FB) {
                   var statusText = '<b>Login status: </b><br/>';
                   FB.getLoginStatus(function(response) {
                           if (response.status === 'connected') {
                             var uid = response.authResponse.userID;
                             var accessToken = response.authResponse.accessToken;
                             var expiration = response.authResponse.expiresIn;
                             statusText += 'Logged in as: ' + uid + '<br/>';
                             statusText += 'Access token: ' + accessToken + '<br/>';
                             statusText += 'Expires in: ' + expiration ;
                           } else if (response.status === 'not_authorized') {
                             statusText += 'Not authorized';
                           } else {
                             statusText += 'Not logged into Facebook.';
                           }
                          });
                                         
                   statusText += '<br/><br/>';
               
                   $('#currentStatus').html(statusText);
               
           }
           
           function userInfo(FB){
                   var statusText = '<b>User Data: (You can pull whatever data the end user agrees to provide.' +  
                                   'The JSON response is included below...)</b><br/>';
                   FB.api('/me', function(response) {
                       
                           var name = response.name ;
                           var email = response.email;
                           var responseText = response.toSource();
                       
                           statusText += 'Name: ' + name + '<br/>' ;
                           statusText += 'Email: ' + email + '<br/><br/>';
                       
                           statusText += 'Response: ' + responseText + '<br/>';
                           statusText += '<br/><br/>'
                   $('div#userStuff').html(statusText);
                   });
           }
         </script>
    <h2>My BSides Facebook OAuth Demo</h2>
    <p>Want In??</p>
    <!--  This is where you can ask for a few things user_location,email, mail_box!!! -->
    <div class="fb-login-button" scope="email,user_likes,user_location">Login to BSide
            with Facebook Creds</div>
    <br />
    <div id="currentStatus"></div>
    <br/>
    <div id="userStuff"></div>
    <span id="refreshStatus" style="color: #FF0000" >Refresh
            Status</span>
    <br />
    <br />
    <br />
    <a href="/logout.html" onclick="FB.logout();">Logout</a>
</body>
</html>

Twitter

Twitter also uses different forms of OAuth for authentication.

Other OAuth Implementations

OAuth Ruby Gem - http://oauth.rubyforge.org/

~