Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merging master.

  • Loading branch information...
commit 3dbfdff12742d3517a9add28701986236dfb70be 2 parents 6748a0c + e015844
Michael Bleigh authored September 03, 2011

Showing 68 changed files with 2,204 additions and 241 deletions. Show diff stats Hide diff stats

  1. 9  .autotest
  2. 3  .travis.yml
  3. 27  Guardfile
  4. 19  LICENSE
  5. 49  README.md
  6. 0  Rakefile
  7. 1  lib/oa-core.rb
  8. 33  lib/omniauth/builder.rb
  9. 140  lib/omniauth/core.rb
  10. 186  lib/omniauth/form.rb
  11. 230  lib/omniauth/strategy.rb
  12. 12  lib/omniauth/test.rb
  13. 8  lib/omniauth/test/phony_session.rb
  14. 34  lib/omniauth/test/strategy_macros.rb
  15. 49  lib/omniauth/test/strategy_test_case.rb
  16. 15  oa-core/lib/omniauth/core.rb
  17. 2  oa-core/lib/omniauth/strategy.rb
  18. 17  oa-core/oa-core.gemspec
  19. 5  oa-core/spec/omniauth/strategy_spec.rb
  20. 35  oa-enterprise/README.rdoc
  21. 1  oa-enterprise/lib/omniauth/enterprise.rb
  22. 4  oa-enterprise/lib/omniauth/strategies/ldap/adaptor.rb
  23. 50  oa-enterprise/lib/omniauth/strategies/saml.rb
  24. 38  oa-enterprise/lib/omniauth/strategies/saml/auth_request.rb
  25. 141  oa-enterprise/lib/omniauth/strategies/saml/auth_response.rb
  26. 8  oa-enterprise/lib/omniauth/strategies/saml/validation_error.rb
  27. 126  oa-enterprise/lib/omniauth/strategies/saml/xml_security.rb
  28. 38  oa-enterprise/oa-enterprise.gemspec
  29. 37  oa-enterprise/spec/omniauth/strategies/saml_spec.rb
  30. 1  oa-identity/oa-identity.gemspec
  31. 9  oa-more/lib/omniauth/more.rb
  32. 86  oa-more/lib/omniauth/strategies/flickr.rb
  33. 28  oa-more/oa-more.gemspec
  34. 7  oa-more/spec/omniauth/strategies/flickr_spec.rb
  35. 12  oa-oauth/lib/omniauth/oauth.rb
  36. 59  oa-oauth/lib/omniauth/strategies/google_oauth2.rb
  37. 4  oa-oauth/lib/omniauth/strategies/oauth.rb
  38. 2  oa-oauth/lib/omniauth/strategies/oauth/dropbox.rb
  39. 39  oa-oauth/lib/omniauth/strategies/oauth/flickr.rb
  40. 1  oa-oauth/lib/omniauth/strategies/oauth/t163.rb
  41. 4  oa-oauth/lib/omniauth/strategies/oauth/tsina.rb
  42. 57  oa-oauth/lib/omniauth/strategies/oauth2/angellist.rb
  43. 2  oa-oauth/lib/omniauth/strategies/oauth2/foursquare.rb
  44. 1  oa-oauth/lib/omniauth/strategies/oauth2/instagram.rb
  45. 67  oa-oauth/lib/omniauth/strategies/oauth2/liveid.rb
  46. 39  oa-oauth/lib/omniauth/strategies/oauth2/mailchimp.rb
  47. 3  oa-oauth/lib/omniauth/strategies/oauth2/salesforce.rb
  48. 14  oa-oauth/lib/omniauth/strategies/{oauth → oauth2}/sound_cloud.rb
  49. 5  oa-oauth/lib/omniauth/strategies/oauth2/taobao.rb
  50. 72  oa-oauth/lib/omniauth/strategies/oauth2/viadeo.rb
  51. 34  oa-oauth/oa-oauth.gemspec
  52. 5  oa-oauth/spec/omniauth/strategies/google_oauth2_spec.rb
  53. 6  oa-oauth/spec/omniauth/strategies/oauth/flickr_spec.rb
  54. 26  oa-oauth/spec/omniauth/strategies/oauth/oauth_spec.rb
  55. 5  oa-oauth/spec/omniauth/strategies/oauth2/angellist_spec.rb
  56. 5  oa-oauth/spec/omniauth/strategies/oauth2/instagram_spec.rb
  57. 5  oa-oauth/spec/omniauth/strategies/oauth2/liveid_spec.rb
  58. 6  oa-oauth/spec/omniauth/strategies/oauth2/mailchimp_spec.rb
  59. 2  oa-oauth/spec/omniauth/strategies/{oauth → oauth2}/sound_cloud_spec.rb
  60. 2  oa-oauth/spec/omniauth/strategies/oauth2/taobao_spec.rb
  61. 5  oa-oauth/spec/omniauth/strategies/oauth2/viadeo_spec.rb
  62. 6  oa-openid/lib/omniauth/strategies/open_id.rb
  63. 26  oa-openid/oa-openid.gemspec
  64. 4  omniauth.gemspec
  65. 20  spec/omniauth/builder_spec.rb
  66. 79  spec/omniauth/core_spec.rb
  67. 368  spec/omniauth/strategy_spec.rb
  68. 12  spec/spec_helper.rb
9  .autotest
... ...
@@ -1,9 +0,0 @@
1  
-require 'autotest/bundler'
2  
-
3  
-Autotest.add_hook :initialize do |at|
4  
-  at.clear_mappings
5  
-
6  
-  at.add_mapping(%r{^.*/spec/.*_spec.rb$}) do |filename, _|
7  
-    filename
8  
-  end
9  
-end
3  .travis.yml
... ...
@@ -1,4 +1,7 @@
1 1
 rvm:
2 2
   - 1.8.7
3 3
   - 1.9.2
  4
+  - jruby
  5
+  - rbx
  6
+  - rbx-2.0
4 7
   - ree
27  Guardfile
... ...
@@ -0,0 +1,27 @@
  1
+# A sample Guardfile
  2
+# More info at https://github.com/guard/guard#readme
  3
+
  4
+guard 'rspec', :version => 2 do
  5
+  watch(%r{^spec/.+_spec\.rb$})
  6
+  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  7
+  watch('spec/spec_helper.rb')  { "spec/" }
  8
+
  9
+  # Rails example
  10
+  watch(%r{^spec/.+_spec\.rb$})
  11
+  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  12
+  watch(%r{^lib/(.+)\.rb$})                           { |m| "spec/lib/#{m[1]}_spec.rb" }
  13
+  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  14
+  watch(%r{^spec/support/(.+)\.rb$})                  { "spec/" }
  15
+  watch('spec/spec_helper.rb')                        { "spec/" }
  16
+  watch('config/routes.rb')                           { "spec/routing" }
  17
+  watch('app/controllers/application_controller.rb')  { "spec/controllers" }
  18
+  # Capybara request specs
  19
+  watch(%r{^app/views/(.+)/.*\.(erb|haml)$})          { |m| "spec/requests/#{m[1]}_spec.rb" }
  20
+end
  21
+
  22
+
  23
+guard 'bundler' do
  24
+  watch('Gemfile')
  25
+  # Uncomment next line if Gemfile contain `gemspec' command
  26
+  # watch(/^.+\.gemspec/)
  27
+end
19  LICENSE
... ...
@@ -0,0 +1,19 @@
  1
+Copyright (c) 2010-2011 Michael Bleigh and Intridea, Inc.
  2
+
  3
+Permission is hereby granted, free of charge, to any person obtaining a copy
  4
+of this software and associated documentation files (the "Software"), to deal
  5
+in the Software without restriction, including without limitation the rights
  6
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7
+copies of the Software, and to permit persons to whom the Software is
  8
+furnished to do so, subject to the following conditions:
  9
+
  10
+The above copyright notice and this permission notice shall be included in
  11
+all copies or substantial portions of the Software.
  12
+
  13
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19
+THE SOFTWARE.
49  README.md
Source Rendered
... ...
@@ -1,5 +1,4 @@
1  
-OmniAuth: Standardized Multi-Provider Authentication
2  
-====================================================
  1
+# OmniAuth: Standardized Multi-Provider Authentication
3 2
 OmniAuth is a new Rack-based authentication system for multi-provider external
4 3
 authentcation. OmniAuth is built from the ground up on the philosophy that
5 4
 **authentication is not the same as identity**, and is based on two
@@ -13,22 +12,20 @@ observations:
13 12
    to one, three, or twelve other services. Modern authentication systems
14 13
    should allow a user's identity to be associated with many authentications.
15 14
 
16  
-Installation
17  
-------------
  15
+## <a name="installation">Installation</a>
18 16
 To install OmniAuth, simply install the gem:
19 17
 
20 18
     gem install omniauth
21 19
 
22  
-Continuous Integration
23  
-----------------------
24  
-[![Build Status](https://secure.travis-ci.org/intridea/omniauth.png)](http://travis-ci.org/intridea/omniauth)
  20
+## <a name="ci">Continuous Integration</a>
  21
+[![Build Status](https://travis-ci.org/intridea/omniauth.png)](http://travis-ci.org/intridea/omniauth)
25 22
 
26  
-Providers
27  
----------
  23
+## <a name="providers">Providers</a>
28 24
 OmniAuth currently supports the following external providers:
29 25
 
30 26
 * via OAuth (OAuth 1.0, OAuth 2, and xAuth)
31 27
   * 37signals ID (credit: [mbleigh](https://github.com/mbleigh))
  28
+  * AngelList (credit: [joshuaxls](https://github.com/joshuaxls))
32 29
   * Bit.ly (credit: [philnash](https://github.com/philnash))
33 30
   * Blogger (credit: [dsueiro-backing](https://github.com/dsueiro-backing))
34 31
   * Cobot (credit: [kamal](https://github.com/kamal))
@@ -51,6 +48,7 @@ OmniAuth currently supports the following external providers:
51 48
   * Instapaper (credit: [micpringle](https://github.com/micpringle))
52 49
   * LastFM (credit: [tictoc](https://github.com/tictoc))
53 50
   * LinkedIn (credit: [mbleigh](https://github.com/mbleigh))
  51
+  * Mailchimp (via [srbiv](http://github.com/srbiv))
54 52
   * Mailru (credit: [lexer](https://github.com/lexer))
55 53
   * Meetup (credit [coderoshi](https://github.com/coderoshi))
56 54
   * Miso (credit: [rickenharp](https://github.com/rickenharp))
@@ -74,6 +72,7 @@ OmniAuth currently supports the following external providers:
74 72
   * Tsohu (credit: [quake](https://github.com/quake))
75 73
   * Tumblr (credit: [jamiew](https://github.com/jamiew))
76 74
   * Twitter (credit: [mbleigh](https://github.com/mbleigh))
  75
+  * Viadeo (credit: [guillaug](https://github.com/guillaug))
77 76
   * Vimeo (credit: [jamiew](https://github.com/jamiew))
78 77
   * Vkontakte (credit: [german](https://github.com/german))
79 78
   * WePay (credit: [ryanwood](https://github.com/ryanwood))
@@ -88,19 +87,7 @@ OmniAuth currently supports the following external providers:
88 87
 * OpenID (credit: [mbleigh](https://github.com/mbleigh))
89 88
 * Yupoo (credit: [chouti](https://github.com/chouti))
90 89
 
91  
-Compatibility
92  
--------------
93  
-OmniAuth is tested against the following Ruby versions:
94  
-
95  
-* 1.8.7
96  
-* 1.9.1
97  
-* 1.9.2
98  
-* JRuby (note, the Evernote strategy is not available for JRuby)
99  
-* Rubinius
100  
-* REE
101  
-
102  
-Usage
103  
------
  90
+## <a name="usage">Usage</a>
104 91
 OmniAuth is a collection of Rack middleware. To use a single strategy, you simply need to add the middleware:
105 92
 
106 93
     require 'oa-oauth'
@@ -126,8 +113,7 @@ The hash in question will look something like this:
126 113
 
127 114
 The `user_info` hash will automatically be populated with as much information about the user as OmniAuth was able to pull from the given API or authentication provider.
128 115
 
129  
-Resources
130  
----------
  116
+## <a name="resources">Resources</a>
131 117
 The best place to find more information is the [OmniAuth Wiki](https://github.com/intridea/omniauth/wiki). Some specific information you might be interested in:
132 118
 
133 119
 * [CI Build Status](http://travis-ci.org/intridea/omniauth)
@@ -136,20 +122,20 @@ The best place to find more information is the [OmniAuth Wiki](https://github.co
136 122
 * [Report Issues](https://github.com/intridea/omniauth/issues)
137 123
 * [Mailing List](http://groups.google.com/group/omniauth)
138 124
 
139  
-OmniAuth Core
140  
--------------
  125
+## <a name="core">Core Team</a>
141 126
 * **Michael Bleigh** ([mbleigh](https://github.com/mbleigh))
142 127
 * **Erik Michaels-Ober** ([sferik](https://github.com/sferik))
143 128
 
144  
-Supported Rubies
145  
-----------------
  129
+## <a name="rubies">Supported Rubies</a>
146 130
 This library aims to support and is [tested
147 131
 against](http://travis-ci.org/intridea/omniauth) the following Ruby
148 132
 implementations:
149 133
 
150 134
 * Ruby 1.8.7
151 135
 * Ruby 1.9.2
152  
-* Ruby Enterprise Edition 1.8.7
  136
+* [JRuby](http://www.jruby.org/)
  137
+* [Rubinius](http://rubini.us/)
  138
+* [Ruby Enterprise Edition](http://www.rubyenterpriseedition.com/)
153 139
 
154 140
 If something doesn't work on one of these interpreters, it should be considered
155 141
 a bug.
@@ -165,6 +151,5 @@ implementation, you will be personally responsible for providing patches in a
165 151
 timely fashion. If critical issues for a particular implementation exist at the
166 152
 time of a major release, support for that Ruby version may be dropped.
167 153
 
168  
-License
169  
--------
170  
-OmniAuth is licensed under the MIT License.
  154
+## <a name="license">License</a>
  155
+OmniAuth is released under the MIT License.
0  Rakefile 100644 → 100755
File mode changed
1  lib/oa-core.rb
... ...
@@ -0,0 +1 @@
  1
+require 'omniauth/core'
33  lib/omniauth/builder.rb
... ...
@@ -0,0 +1,33 @@
  1
+require 'omniauth/core'
  2
+
  3
+module OmniAuth
  4
+  class Builder < ::Rack::Builder
  5
+    def initialize(app, &block)
  6
+      @app = app
  7
+      super(&block)
  8
+    end
  9
+
  10
+    def on_failure(&block)
  11
+      OmniAuth.config.on_failure = block
  12
+    end
  13
+
  14
+    def configure(&block)
  15
+      OmniAuth.configure(&block)
  16
+    end
  17
+
  18
+    def provider(klass, *args, &block)
  19
+      if klass.is_a?(Class)
  20
+        middleware = klass
  21
+      else
  22
+        middleware = OmniAuth::Strategies.const_get("#{OmniAuth::Utils.camelize(klass.to_s)}")
  23
+      end
  24
+
  25
+      use middleware, *args, &block
  26
+    end
  27
+
  28
+    def call(env)
  29
+      @ins << @app unless @ins.include?(@app)
  30
+      to_app.call(env)
  31
+    end
  32
+  end
  33
+end
140  lib/omniauth/core.rb
... ...
@@ -0,0 +1,140 @@
  1
+require 'rack'
  2
+require 'singleton'
  3
+
  4
+module OmniAuth
  5
+  module Strategies; end
  6
+
  7
+  autoload :Builder,  'omniauth/builder'
  8
+  autoload :Strategy, 'omniauth/strategy'
  9
+  autoload :Test,     'omniauth/test'
  10
+  autoload :Form,     'omniauth/form'
  11
+
  12
+  def self.strategies
  13
+    @@strategies ||= []
  14
+  end
  15
+
  16
+  class Configuration
  17
+    include Singleton
  18
+
  19
+    @@defaults = {
  20
+      :path_prefix => '/auth',
  21
+      :on_failure => Proc.new do |env|
  22
+        message_key = env['omniauth.error.type']
  23
+        new_path = "#{OmniAuth.config.path_prefix}/failure?message=#{message_key}"
  24
+        [302, {'Location' => new_path, 'Content-Type'=> 'text/html'}, []]
  25
+      end,
  26
+      :form_css => Form::DEFAULT_CSS,
  27
+      :test_mode => false,
  28
+      :allowed_request_methods => [:get, :post],
  29
+      :mock_auth => {
  30
+        :default => {
  31
+          'provider' => 'default',
  32
+          'uid' => '1234',
  33
+          'user_info' => {
  34
+            'name' => 'Bob Example'
  35
+          }
  36
+        }
  37
+      }
  38
+    }
  39
+
  40
+    def self.defaults
  41
+      @@defaults
  42
+    end
  43
+
  44
+    def initialize
  45
+      @@defaults.each_pair{|k,v| self.send("#{k}=",v)}
  46
+    end
  47
+
  48
+    def on_failure(&block)
  49
+      if block_given?
  50
+        @on_failure = block
  51
+      else
  52
+        @on_failure
  53
+      end
  54
+    end
  55
+
  56
+    def add_mock(provider, mock={})
  57
+      # Stringify keys recursively one level.
  58
+      mock.keys.each do |key|
  59
+        mock[key.to_s] = mock.delete(key)
  60
+      end
  61
+      mock.each_pair do |key, val|
  62
+        if val.is_a? Hash
  63
+          val.keys.each do |subkey|
  64
+            val[subkey.to_s] = val.delete(subkey)
  65
+          end
  66
+        end
  67
+      end
  68
+
  69
+      # Merge with the default mock and ensure provider is correct.
  70
+      mock = self.mock_auth[:default].dup.merge(mock)
  71
+      mock["provider"] = provider.to_s
  72
+
  73
+      # Add it to the mocks.
  74
+      self.mock_auth[provider.to_sym] = mock
  75
+    end
  76
+
  77
+    attr_writer :on_failure
  78
+    attr_accessor :path_prefix, :allowed_request_methods, :form_css, :test_mode, :mock_auth, :full_host
  79
+  end
  80
+
  81
+  def self.config
  82
+    Configuration.instance
  83
+  end
  84
+
  85
+  def self.configure
  86
+    yield config
  87
+  end
  88
+
  89
+  def self.mock_auth_for(provider)
  90
+    config.mock_auth[provider.to_sym] || config.mock_auth[:default]
  91
+  end
  92
+
  93
+  module Utils
  94
+    CAMELIZE_SPECIAL = {
  95
+      'oauth' => 'OAuth',
  96
+      'oauth2' => 'OAuth2',
  97
+      'openid' => 'OpenID',
  98
+      'open_id' => 'OpenID',
  99
+      'github' => 'GitHub',
  100
+      'tripit' => 'TripIt',
  101
+      'soundcloud' => 'SoundCloud',
  102
+      'smugmug' => 'SmugMug',
  103
+      'cas' => 'CAS',
  104
+      'trademe' => 'TradeMe',
  105
+      'ldap'  => 'LDAP',
  106
+      'google_oauth2' => 'GoogleOAuth2'
  107
+    }
  108
+
  109
+    module_function
  110
+
  111
+    def form_css
  112
+      "<style type='text/css'>#{OmniAuth.config.form_css}</style>"
  113
+    end
  114
+
  115
+    def deep_merge(hash, other_hash)
  116
+      target = hash.dup
  117
+
  118
+      other_hash.keys.each do |key|
  119
+        if other_hash[key].is_a? ::Hash and hash[key].is_a? ::Hash
  120
+          target[key] = deep_merge(target[key],other_hash[key])
  121
+          next
  122
+        end
  123
+
  124
+        target[key] = other_hash[key]
  125
+      end
  126
+
  127
+      target
  128
+    end
  129
+
  130
+    def camelize(word, first_letter_in_uppercase = true)
  131
+      return CAMELIZE_SPECIAL[word.to_s] if CAMELIZE_SPECIAL[word.to_s]
  132
+
  133
+      if first_letter_in_uppercase
  134
+        word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
  135
+      else
  136
+        word.first + camelize(word)[1..-1]
  137
+      end
  138
+    end
  139
+  end
  140
+end
186  lib/omniauth/form.rb
... ...
@@ -0,0 +1,186 @@
  1
+require 'omniauth/core'
  2
+
  3
+module OmniAuth
  4
+  class Form
  5
+    DEFAULT_CSS = <<-CSS
  6
+    body {
  7
+      background: #ccc;
  8
+      font-family: "Lucida Grande", "Lucida Sans", Helvetica, Arial, sans-serif;
  9
+    }
  10
+
  11
+    h1 {
  12
+      text-align: center;
  13
+      margin: 30px auto 0px;
  14
+      font-size: 18px;
  15
+      padding: 10px 10px 15px;
  16
+      background: #555;
  17
+      color: white;
  18
+      width: 320px;
  19
+      border: 10px solid #444;
  20
+      border-bottom: 0;
  21
+      -moz-border-radius-topleft: 10px;
  22
+      -moz-border-radius-topright: 10px;
  23
+      -webkit-border-top-left-radius: 10px;
  24
+      -webkit-border-top-right-radius: 10px;
  25
+      border-top-left-radius: 10px;
  26
+      border-top-right-radius: 10px;
  27
+    }
  28
+
  29
+    h1, form {
  30
+      -moz-box-shadow: 2px 2px 7px rgba(0,0,0,0.3);
  31
+      -webkit-box-shadow: 2px 2px 7px rgba(0,0,0,0.3);
  32
+    }
  33
+
  34
+    form {
  35
+      background: white;
  36
+      border: 10px solid #eee;
  37
+      border-top: 0;
  38
+      padding: 20px;
  39
+      margin: 0px auto 40px;
  40
+      width: 300px;
  41
+      -moz-border-radius-bottomleft: 10px;
  42
+      -moz-border-radius-bottomright: 10px;
  43
+      -webkit-border-bottom-left-radius: 10px;
  44
+      -webkit-border-bottom-right-radius: 10px;
  45
+      border-bottom-left-radius: 10px;
  46
+      border-bottom-right-radius: 10px;
  47
+    }
  48
+
  49
+    label {
  50
+      display: block;
  51
+      font-weight: bold;
  52
+      margin-bottom: 5px;
  53
+    }
  54
+
  55
+    input {
  56
+      font-size: 18px;
  57
+      padding: 4px 8px;
  58
+      display: block;
  59
+      margin-bottom: 10px;
  60
+      width: 280px;
  61
+    }
  62
+
  63
+    input#identifier, input#openid_url {
  64
+      background: url(http://openid.net/login-bg.gif) no-repeat;
  65
+      background-position: 0 50%;
  66
+      padding-left: 18px;
  67
+    }
  68
+
  69
+    button {
  70
+      font-size: 22px;
  71
+      padding: 4px 8px;
  72
+      display: block;
  73
+      margin: 20px auto 0;
  74
+    }
  75
+
  76
+    fieldset {
  77
+      border: 1px solid #ccc;
  78
+      border-left: 0;
  79
+      border-right: 0;
  80
+      padding: 10px 0;
  81
+    }
  82
+
  83
+    fieldset input {
  84
+      width: 260px;
  85
+      font-size: 16px;
  86
+    }
  87
+    CSS
  88
+
  89
+    attr_accessor :options
  90
+
  91
+    def initialize(options = {})
  92
+      options[:title] ||= "Authentication Info Required"
  93
+      options[:header_info] ||= ""
  94
+      self.options = options
  95
+
  96
+      @html = ""
  97
+      header(options[:title],options[:header_info])
  98
+    end
  99
+
  100
+    def self.build(title=nil,&block)
  101
+      form = OmniAuth::Form.new(title)
  102
+      form.instance_eval(&block)
  103
+    end
  104
+
  105
+    def label_field(text, target)
  106
+      @html << "\n<label for='#{target}'>#{text}:</label>"
  107
+      self
  108
+    end
  109
+
  110
+    def input_field(type, name)
  111
+      @html << "\n<input type='#{type}' id='#{name}' name='#{name}'/>"
  112
+      self
  113
+    end
  114
+
  115
+    def text_field(label, name)
  116
+      label_field(label, name)
  117
+      input_field('text', name)
  118
+      self
  119
+    end
  120
+
  121
+    def password_field(label, name)
  122
+      label_field(label, name)
  123
+      input_field('password', name)
  124
+      self
  125
+    end
  126
+
  127
+    def button(text)
  128
+      @html << "\n<button type='submit'>#{text}</button>"
  129
+    end
  130
+
  131
+    def html(html)
  132
+      @html << html
  133
+    end
  134
+
  135
+    def fieldset(legend, options = {}, &block)
  136
+      @html << "\n<fieldset#{" style='#{options[:style]}'" if options[:style]}#{" id='#{options[:id]}'" if options[:id]}>\n  <legend>#{legend}</legend>\n"
  137
+      self.instance_eval &block
  138
+      @html << "\n</fieldset>"
  139
+      self
  140
+    end
  141
+
  142
+    def header(title,header_info)
  143
+      @html << <<-HTML
  144
+      <!DOCTYPE html>
  145
+      <html>
  146
+      <head>
  147
+        <title>#{title}</title>
  148
+        #{css}
  149
+        #{header_info}
  150
+      </head>
  151
+      <body>
  152
+      <h1>#{title}</h1>
  153
+      <form method='post' #{"action='#{options[:url]}' " if options[:url]}noValidate='noValidate'>
  154
+      HTML
  155
+      self
  156
+    end
  157
+
  158
+    def footer
  159
+      return self if @footer
  160
+      @html << <<-HTML
  161
+      <button type='submit'>Connect</button>
  162
+      </form>
  163
+      </body>
  164
+      </html>
  165
+      HTML
  166
+      @footer = true
  167
+      self
  168
+    end
  169
+
  170
+    def to_html
  171
+      footer
  172
+      @html
  173
+    end
  174
+
  175
+    def to_response
  176
+      footer
  177
+      Rack::Response.new(@html).finish
  178
+    end
  179
+
  180
+    protected
  181
+
  182
+    def css
  183
+      "\n<style type='text/css'>#{OmniAuth.config.form_css}</style>"
  184
+    end
  185
+  end
  186
+end
230  lib/omniauth/strategy.rb
... ...
@@ -0,0 +1,230 @@
  1
+require 'omniauth/core'
  2
+
  3
+module OmniAuth
  4
+  class NoSessionError < StandardError; end
  5
+  # The Strategy is the base unit of OmniAuth's ability to
  6
+  # wrangle multiple providers. Each strategy provided by
  7
+  # OmniAuth includes this mixin to gain the default functionality
  8
+  # necessary to be compatible with the OmniAuth library.
  9
+  module Strategy
  10
+    def self.included(base)
  11
+      OmniAuth.strategies << base
  12
+      base.class_eval do
  13
+        attr_reader :app, :name, :env, :options, :response
  14
+      end
  15
+    end
  16
+
  17
+    def initialize(app, name, *args, &block)
  18
+      @app = app
  19
+      @name = name.to_sym
  20
+      @options = args.last.is_a?(Hash) ? args.pop : {}
  21
+
  22
+      yield self if block_given?
  23
+    end
  24
+
  25
+    def inspect
  26
+      "#<#{self.class.to_s}>"
  27
+    end
  28
+
  29
+    def call(env)
  30
+      dup.call!(env)
  31
+    end
  32
+
  33
+    def call!(env)
  34
+      raise OmniAuth::NoSessionError.new("You must provide a session to use OmniAuth.") unless env['rack.session']
  35
+
  36
+      @env = env
  37
+      @env['omniauth.strategy'] = self if on_auth_path?
  38
+
  39
+      return mock_call!(env) if OmniAuth.config.test_mode
  40
+
  41
+      return request_call if on_request_path? && OmniAuth.config.allowed_request_methods.include?(request.request_method.downcase.to_sym)
  42
+      return callback_call if on_callback_path?
  43
+      return other_phase if respond_to?(:other_phase)
  44
+      @app.call(env)
  45
+    end
  46
+
  47
+    # Performs the steps necessary to run the request phase of a strategy.
  48
+    def request_call
  49
+      setup_phase
  50
+      if response = call_through_to_app
  51
+        response
  52
+      else
  53
+        if request.params['origin']
  54
+          @env['rack.session']['omniauth.origin'] = request.params['origin']
  55
+        elsif env['HTTP_REFERER'] && !env['HTTP_REFERER'].match(/#{request_path}$/)
  56
+          @env['rack.session']['omniauth.origin'] = env['HTTP_REFERER']
  57
+        end
  58
+        request_phase
  59
+      end
  60
+    end
  61
+
  62
+    # Performs the steps necessary to run the callback phase of a strategy.
  63
+    def callback_call
  64
+      setup_phase
  65
+      @env['omniauth.origin'] = session.delete('omniauth.origin')
  66
+      @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
  67
+
  68
+      callback_phase
  69
+    end
  70
+
  71
+    def on_auth_path?
  72
+      on_request_path? || on_callback_path?
  73
+    end
  74
+
  75
+    def on_request_path?
  76
+      current_path.casecmp(request_path) == 0
  77
+    end
  78
+
  79
+    def on_callback_path?
  80
+      current_path.casecmp(callback_path) == 0
  81
+    end
  82
+
  83
+    def mock_call!(env)
  84
+      return mock_request_call if on_request_path?
  85
+      return mock_callback_call if on_callback_path?
  86
+      call_app!
  87
+    end
  88
+
  89
+    def mock_request_call
  90
+      setup_phase
  91
+      return response if response = call_through_to_app
  92
+
  93
+      if request.params['origin']
  94
+        @env['rack.session']['omniauth.origin'] = request.params['origin']
  95
+      elsif env['HTTP_REFERER'] && !env['HTTP_REFERER'].match(/#{request_path}$/)
  96
+        @env['rack.session']['omniauth.origin'] = env['HTTP_REFERER']
  97
+      end
  98
+      redirect(script_name + callback_path + query_string)
  99
+    end
  100
+
  101
+    def mock_callback_call
  102
+      setup_phase
  103
+      mocked_auth = OmniAuth.mock_auth_for(name.to_sym)
  104
+      if mocked_auth.is_a?(Symbol)
  105
+        fail!(mocked_auth)
  106
+      else
  107
+        @env['omniauth.auth'] = mocked_auth
  108
+        @env['omniauth.origin'] = session.delete('omniauth.origin')
  109
+        @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
  110
+        call_app!
  111
+      end
  112
+    end
  113
+
  114
+    def setup_phase
  115
+      if options[:setup].respond_to?(:call)
  116
+        options[:setup].call(env)
  117
+      elsif options[:setup]
  118
+        setup_env = env.merge('PATH_INFO' => setup_path, 'REQUEST_METHOD' => 'GET')
  119
+        call_app!(setup_env)
  120
+      end
  121
+    end
  122
+
  123
+    def request_phase
  124
+      raise NotImplementedError
  125
+    end
  126
+
  127
+    def callback_phase
  128
+      @env['omniauth.auth'] = auth_hash
  129
+      @env['omniauth.params'] = session['query_params'] || {}
  130
+      session['query_params'] = nil if session['query_params']
  131
+      call_app!
  132
+    end
  133
+
  134
+    def path_prefix
  135
+      options[:path_prefix] || OmniAuth.config.path_prefix
  136
+    end
  137
+
  138
+    def request_path
  139
+      options[:request_path] || "#{path_prefix}/#{name}"
  140
+    end
  141
+
  142
+    def callback_path
  143
+      options[:callback_path] || "#{path_prefix}/#{name}/callback"
  144
+    end
  145
+
  146
+    def setup_path
  147
+      options[:setup_path] || "#{path_prefix}/#{name}/setup"
  148
+    end
  149
+
  150
+    def current_path
  151
+      request.path_info.downcase.sub(/\/$/,'')
  152
+    end
  153
+
  154
+    def query_string
  155
+      request.query_string.empty? ? "" : "?#{request.query_string}"
  156
+    end
  157
+
  158
+    def call_through_to_app
  159
+      status, headers, body = *call_app!
  160
+      session['query_params'] = Rack::Request.new(env).params
  161
+      @response = Rack::Response.new(body, status, headers)
  162
+
  163
+      status == 404 ? nil : @response.finish
  164
+    end
  165
+
  166
+    def call_app!(env = @env)
  167
+      @app.call(env)
  168
+    end
  169
+
  170
+    def auth_hash
  171
+      {
  172
+        'provider' => name.to_s,
  173
+        'uid' => nil
  174
+      }
  175
+    end
  176
+
  177
+    def full_host
  178
+      case OmniAuth.config.full_host
  179
+        when String
  180
+          OmniAuth.config.full_host
  181
+        when Proc
  182
+          OmniAuth.config.full_host.call(env)
  183
+        else
  184
+          uri = URI.parse(request.url.gsub(/\?.*$/,''))
  185
+          uri.path = ''
  186
+          uri.query = nil
  187
+          uri.to_s
  188
+      end
  189
+    end
  190
+
  191
+    def callback_url
  192
+      full_host + script_name + callback_path + query_string
  193
+    end
  194
+
  195
+    def script_name
  196
+      @env['SCRIPT_NAME'] || ''
  197
+    end
  198
+
  199
+    def session
  200
+      @env['rack.session']
  201
+    end
  202
+
  203
+    def request
  204
+      @request ||= Rack::Request.new(@env)
  205
+    end
  206
+
  207
+    def redirect(uri)
  208
+      r = Rack::Response.new
  209
+
  210
+      if options[:iframe]
  211
+        r.write("<script type='text/javascript' charset='utf-8'>top.location.href = '#{uri}';</script>")
  212
+      else
  213
+        r.write("Redirecting to #{uri}...")
  214
+        r.redirect(uri)
  215
+      end
  216
+
  217
+      r.finish
  218
+    end
  219
+
  220
+    def user_info; {} end
  221
+
  222
+    def fail!(message_key, exception = nil)
  223
+      self.env['omniauth.error'] = exception
  224
+      self.env['omniauth.error.type'] = message_key.to_sym
  225
+      self.env['omniauth.error.strategy'] = self
  226
+
  227
+      OmniAuth.config.on_failure.call(self.env)
  228
+    end
  229
+  end
  230
+end
12  lib/omniauth/test.rb
... ...
@@ -0,0 +1,12 @@
  1
+module OmniAuth
  2
+
  3
+  # Support for testing OmniAuth strategies.
  4
+  module Test
  5
+
  6
+    autoload :PhonySession,     'omniauth/test/phony_session'
  7
+    autoload :StrategyMacros,   'omniauth/test/strategy_macros'
  8
+    autoload :StrategyTestCase, 'omniauth/test/strategy_test_case'
  9
+
  10
+  end
  11
+
  12
+end
8  lib/omniauth/test/phony_session.rb
... ...
@@ -0,0 +1,8 @@
  1
+class OmniAuth::Test::PhonySession
  2
+  def initialize(app); @app = app end
  3
+  def call(env)
  4
+    @session ||= (env['rack.session'] || {})
  5
+    env['rack.session'] = @session
  6
+    @app.call(env)
  7
+  end
  8
+end
34  lib/omniauth/test/strategy_macros.rb
... ...
@@ -0,0 +1,34 @@
  1
+module OmniAuth
  2
+
  3
+  module Test
  4
+
  5
+    module StrategyMacros
  6
+
  7
+      def sets_an_auth_hash
  8
+        it 'should set an auth hash' do
  9
+          last_request.env['omniauth.auth'].should be_kind_of(Hash)
  10
+        end
  11
+      end
  12
+
  13
+      def sets_provider_to(provider)
  14
+        it "should set the provider to #{provider}" do
  15
+          (last_request.env['omniauth.auth'] || {})['provider'].should == provider
  16
+        end
  17
+      end
  18
+
  19
+      def sets_uid_to(uid)
  20
+        it "should set the UID to #{uid}" do
  21
+          (last_request.env['omniauth.auth'] || {})['uid'].should == uid
  22
+        end
  23
+      end
  24
+
  25
+      def sets_user_info_to(user_info)
  26
+        it "should set the user_info to #{user_info}" do
  27
+          (last_request.env['omniauth.auth'] || {})['user_info'].should == user_info
  28
+        end
  29
+      end
  30
+    end
  31
+
  32
+  end
  33
+
  34
+end
49  lib/omniauth/test/strategy_test_case.rb
... ...
@@ -0,0 +1,49 @@
  1
+require 'rack'
  2
+require 'omniauth/test'
  3
+
  4
+module OmniAuth
  5
+
  6
+  module Test
  7
+
  8
+    # Support for testing OmniAuth strategies.
  9
+    #
  10
+    # @example Usage
  11
+    #   class MyStrategyTest < Test::Unit::TestCase
  12
+    #     include OmniAuth::Test::StrategyTestCase
  13
+    #     def strategy
  14
+    #       # return the parameters to a Rack::Builder map call:
  15
+    #       [MyStrategy.new, :some, :configuration, :options => 'here']
  16
+    #     end
  17
+    #     setup do
  18
+    #       post '/auth/my_strategy/callback', :user => { 'name' => 'Dylan', 'id' => '445' }
  19
+    #     end
  20
+    #   end
  21
+    module StrategyTestCase
  22
+
  23
+      def app
  24
+        strat = self.strategy
  25
+        resp = self.app_response
  26
+        Rack::Builder.new {
  27
+          use OmniAuth::Test::PhonySession
  28
+          use *strat
  29
+          run lambda {|env| [404, {'Content-Type' => 'text/plain'}, [resp || env.key?('omniauth.auth').to_s]] }
  30
+        }.to_app
  31
+      end
  32
+
  33
+      def app_response
  34
+        nil
  35
+      end
  36
+
  37
+      def session
  38
+        last_request.env['rack.session']
  39
+      end
  40
+
  41
+      def strategy
  42
+        raise NotImplementedError.new('Including specs must define #strategy')
  43
+      end
  44
+
  45
+    end
  46
+
  47
+  end
  48
+
  49
+end
15  oa-core/lib/omniauth/core.rb
@@ -56,10 +56,14 @@ def on_failure(&block)
56 56
 
57 57
     def add_mock(provider, mock={})
58 58
       # Stringify keys recursively one level.
59  
-      mock.stringify_keys!
60  
-      mock.keys.each do|key|
61  
-        if mock[key].is_a? Hash
62  
-          mock[key].stringify_keys!
  59
+      mock.keys.each do |key|
  60
+        mock[key.to_s] = mock.delete(key)
  61
+      end
  62
+      mock.each_pair do |key, val|
  63
+        if val.is_a? Hash
  64
+          val.keys.each do |subkey|
  65
+            val[subkey.to_s] = val.delete(subkey)
  66
+          end
63 67
         end
64 68
       end
65 69
 
@@ -99,7 +103,8 @@ module Utils
99 103
       'smugmug' => 'SmugMug',
100 104
       'cas' => 'CAS',
101 105
       'trademe' => 'TradeMe',
102  
-      'ldap'  => 'LDAP'
  106
+      'ldap'  => 'LDAP',
  107
+      'google_oauth2' => 'GoogleOAuth2'
103 108
     }
104 109
 
105 110
     module_function
2  oa-core/lib/omniauth/strategy.rb
@@ -110,7 +110,7 @@ def mock_request_call
110 110
       elsif env['HTTP_REFERER'] && !env['HTTP_REFERER'].match(/#{request_path}$/)
111 111
         @env['rack.session']['omniauth.origin'] = env['HTTP_REFERER']
112 112
       end
113  
-      redirect(script_name + callback_path)
  113
+      redirect(script_name + callback_path + query_string)
114 114
     end
115 115
 
116 116
     def mock_callback_call
17  oa-core/oa-core.gemspec
... ...
@@ -1,4 +1,4 @@
1  
-# -*- encoding: utf-8 -*-
  1
+# encoding: utf-8
2 2
 require File.expand_path('../lib/omniauth/version', __FILE__)
3 3
 
4 4
 Gem::Specification.new do |gem|
@@ -9,19 +9,18 @@ Gem::Specification.new do |gem|
9 9
   gem.add_development_dependency 'simplecov', '~> 0.4'
10 10
   gem.add_development_dependency 'rack-test', '~> 0.5'
11 11
   gem.add_development_dependency 'rake', '~> 0.8'
  12
+  gem.add_development_dependency 'rdiscount', '~> 1.6'
12 13
   gem.add_development_dependency 'rspec', '~> 2.5'
13 14
   gem.add_development_dependency 'yard', '~> 0.7'
14  
-  gem.add_development_dependency 'ZenTest', '~> 4.5'
15  
-  gem.name = 'oa-core'
16  
-  gem.version = OmniAuth::Version::STRING
  15
+  gem.authors = ['Michael Bleigh', 'Erik Michaels-Ober']
17 16
   gem.description = %q{Core strategies for OmniAuth.}
18  
-  gem.summary = gem.description
19 17
   gem.email = ['michael@intridea.com', 'sferik@gmail.com']
20  
-  gem.homepage = 'http://github.com/intridea/omniauth'
21  
-  gem.authors = ['Michael Bleigh', 'Erik Michaels-Ober']
22  
-  gem.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
23 18
   gem.files = `git ls-files`.split("\n")
24  
-  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
  19
+  gem.homepage = 'http://github.com/intridea/omniauth'
  20
+  gem.name = 'oa-core'
25 21
   gem.require_paths = ['lib']
26 22
   gem.required_rubygems_version = Gem::Requirement.new('>= 1.3.6') if gem.respond_to? :required_rubygems_version=
  23
+  gem.summary = gem.description
  24
+  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
  25
+  gem.version = OmniAuth::Version::STRING
27 26
 end
5  oa-core/spec/omniauth/strategy_spec.rb
@@ -296,6 +296,11 @@ def make_env(path = '/auth/test', props = {})
296 296
         strategy.call(make_env('/AUTH/TeSt/CaLlBAck')).should == strategy.call(make_env('/auth/test/callback'))
297 297
       end
298 298
 
  299
+      it 'should maintain query string parameters' do
  300
+        response = strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'cheese=stilton'))
  301
+        response[1]['Location'].should == '/auth/test/callback?cheese=stilton'
  302
+      end
  303
+
299 304
       it 'should not short circuit requests outside of authentication' do
300 305
         strategy.call(make_env('/')).should == app.call(make_env('/'))
301 306
       end
35  oa-enterprise/README.rdoc
Source Rendered
@@ -66,7 +66,40 @@ are not familiar with these authentication methods, please just avoid them.
66 66
 
67 67
 Direct users to '/auth/ldap' to have them authenticated via your
68 68
 company's LDAP server.
69  
-    
  69
+
  70
+== SAML
  71
+
  72
+Use the SAML strategy as a middleware in your application:
  73
+
  74
+    require 'omniauth/enterprise'
  75
+    use OmniAuth::Strategies::SAML, 
  76
+        :assertion_consumer_service_url => "consumer_service_url",
  77
+        :issuer                         => "issuer",
  78
+        :idp_sso_target_url             => "idp_sso_target_url",
  79
+        :idp_cert_fingerprint           => "E7:91:B2:E1:...",
  80
+        :name_identifier_format         => "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
  81
+
  82
+:assertion_consumer_service_url 
  83
+  The URL at which the SAML assertion should be received. 
  84
+
  85
+:issuer
  86
+  The name of your application. Some identity providers might need this to establish the 
  87
+  identity of the service provider requesting the login.
  88
+
  89
+:idp_sso_target_url
  90
+  The URL to which the authentication request should be sent. This would be on the identity provider.
  91
+
  92
+:idp_cert_fingerprint
  93
+  The certificate fingerprint, e.g. "90:CC:16:F0:8D:A6:D1:C6:BB:27:2D:BA:93:80:1A:1F:16:8E:4E:08".
  94
+  This is provided from the identity provider when setting up the relationship.
  95
+
  96
+:name_identifier_format
  97
+  Describes the format of the username required by this application. 
  98
+  If you need the email address, use "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress". 
  99
+  See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf section 8.3 for 
  100
+  other options. Note that the identity provider might not support all options.  
  101
+
  102
+
70 103
 == Multiple Strategies
71 104
 
72 105
 If you're using multiple strategies together, use OmniAuth's Builder. That's
1  oa-enterprise/lib/omniauth/enterprise.rb
@@ -4,5 +4,6 @@ module OmniAuth
4 4
   module Strategies
5 5
     autoload :CAS, 'omniauth/strategies/cas'
6 6
     autoload :LDAP, 'omniauth/strategies/ldap'
  7
+    autoload :SAML, 'omniauth/strategies/saml'
7 8
   end
8 9
 end
4  oa-enterprise/lib/omniauth/strategies/ldap/adaptor.rb
@@ -125,12 +125,12 @@ def bound?
125 125
         end
126 126
 
127 127
         def search(options={}, &block)
128  
-          base = options[:base]
  128
+          base = options[:base] || @base
129 129
           filter = options[:filter]
130 130
           limit = options[:limit]
131 131
 
132 132
           args = {
133  
-            :base => @base,
  133
+            :base => base,
134 134
             :filter => filter,
135 135
             :size => limit
136 136
           }
50  oa-enterprise/lib/omniauth/strategies/saml.rb
... ...
@@ -0,0 +1,50 @@
  1
+require 'omniauth/enterprise'
  2
+
  3
+module OmniAuth
  4
+  module Strategies
  5
+    class SAML
  6
+      include OmniAuth::Strategy
  7
+      autoload :AuthRequest,      'omniauth/strategies/saml/auth_request'
  8
+      autoload :AuthResponse,     'omniauth/strategies/saml/auth_response'
  9
+      autoload :ValidationError,  'omniauth/strategies/saml/validation_error'
  10
+      autoload :XMLSecurity,      'omniauth/strategies/saml/xml_security'
  11
+      
  12
+      @@settings = {}
  13
+      
  14
+      def initialize(app, options={})
  15
+        super(app, :saml)
  16
+        @@settings = {
  17
+          :assertion_consumer_service_url => options[:assertion_consumer_service_url],
  18
+          :issuer                         => options[:issuer],
  19
+          :idp_sso_target_url             => options[:idp_sso_target_url],
  20
+          :idp_cert_fingerprint           => options[:idp_cert_fingerprint],
  21
+          :name_identifier_format         => options[:name_identifier_format] || "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
  22
+        }
  23
+      end
  24
+          
  25
+      def request_phase
  26
+        request = OmniAuth::Strategies::SAML::AuthRequest.new
  27
+        redirect(request.create(@@settings))
  28
+      end
  29
+      
  30
+      def callback_phase
  31
+        begin
  32
+          response = OmniAuth::Strategies::SAML::AuthResponse.new(request.params['SAMLResponse'])
  33
+          response.settings = @@settings
  34
+          @name_id  = response.name_id
  35
+          return fail!(:invalid_ticket, 'Invalid SAML Ticket') if @name_id.nil? || @name_id.empty?
  36
+          super
  37
+        rescue ArgumentError => e
  38
+          fail!(:invalid_ticket, 'Invalid SAML Response')
  39
+        end        
  40
+      end
  41
+      
  42
+      def auth_hash
  43
+        OmniAuth::Utils.deep_merge(super, {
  44
+          'uid' => @name_id
  45
+        })
  46
+      end  
  47
+            
  48
+    end
  49
+  end
  50
+end
38  oa-enterprise/lib/omniauth/strategies/saml/auth_request.rb
... ...
@@ -0,0 +1,38 @@
  1
+require "base64"
  2
+require "uuid"
  3
+require "zlib"
  4
+require "cgi"
  5
+
  6
+module OmniAuth
  7
+  module Strategies
  8
+    class SAML
  9
+      class AuthRequest
  10
+        
  11
+        def create(settings, params = {})
  12
+          uuid = "_" + UUID.new.generate
  13
+          time = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
  14
+
  15
+          request =
  16
+            "<samlp:AuthnRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\"#{uuid}\" Version=\"2.0\" IssueInstant=\"#{time}\" ProtocolBinding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" AssertionConsumerServiceURL=\"#{settings[:assertion_consumer_service_url]}\">" +
  17
+            "<saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{settings[:issuer]}</saml:Issuer>\n" +
  18
+            "<samlp:NameIDPolicy xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" Format=\"#{settings[:name_identifier_format]}\" AllowCreate=\"true\"></samlp:NameIDPolicy>\n" +
  19
+            "<samlp:RequestedAuthnContext xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" Comparison=\"exact\">" +
  20
+            "<saml:AuthnContextClassRef xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext>\n" +
  21
+            "</samlp:AuthnRequest>"
  22
+
  23
+          deflated_request  = Zlib::Deflate.deflate(request, 9)[2..-5]
  24
+          base64_request    = Base64.encode64(deflated_request)
  25
+          encoded_request   = CGI.escape(base64_request)
  26
+          request_params    = "?SAMLRequest=" + encoded_request
  27
+
  28
+          params.each_pair do |key, value|
  29
+            request_params << "&#{key}=#{CGI.escape(value.to_s)}"
  30
+          end
  31
+