omniauth-shibboleth-redux 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 694f4cd171999330c94f625a014dbca82311f419b21cf485429caaca8d06bcb2
4
+ data.tar.gz: e1b98e477a51b449405806f4a8572e2f662edebc3f1eba7ad2817bdb3204a0e7
5
+ SHA512:
6
+ metadata.gz: 70d4ab79683cde7be990d27151dcce95718dd84bd03ae4e5d290d025711cd20ea74653ab76e8d52b91a231beb0998a6ca79055bee988cff9c57bda1a2f1d119c
7
+ data.tar.gz: 7cdfb8f2a7a27743487bd79a2923408045cd9bc92e5acf4db1585920161fda228beadc04272c6f7c02a38e6b299cc7535cb04faa53b3fb7f94514ff5e918c03d
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ omniauth-shibboleth-redux (2.0.0)
5
+ omniauth (>= 2.0.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.5.0)
11
+ hashie (5.0.0)
12
+ omniauth (2.1.0)
13
+ hashie (>= 3.4.6)
14
+ rack (>= 2.2.3)
15
+ rack-protection
16
+ rack (3.0.0)
17
+ rack-protection (3.0.5)
18
+ rack
19
+ rack-session (2.0.0)
20
+ rack (>= 3.0.0)
21
+ rack-test (2.0.2)
22
+ rack (>= 1.3)
23
+ rake (13.0.6)
24
+ rspec (3.12.0)
25
+ rspec-core (~> 3.12.0)
26
+ rspec-expectations (~> 3.12.0)
27
+ rspec-mocks (~> 3.12.0)
28
+ rspec-core (3.12.1)
29
+ rspec-support (~> 3.12.0)
30
+ rspec-expectations (3.12.2)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.12.0)
33
+ rspec-mocks (3.12.3)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.12.0)
36
+ rspec-support (3.12.0)
37
+
38
+ PLATFORMS
39
+ arm64-darwin-21
40
+
41
+ DEPENDENCIES
42
+ omniauth-shibboleth-redux!
43
+ rack-session
44
+ rack-test
45
+ rake
46
+ rspec (>= 2.8)
47
+
48
+ BUNDLED WITH
49
+ 2.4.6
data/README.md ADDED
@@ -0,0 +1,222 @@
1
+ # OmniAuth Shibboleth strategy
2
+
3
+ OmniAuth Shibboleth strategy is an OmniAuth strategy for authenticating through Shibboleth (SAML). If you do not know OmniAuth, please visit OmniAuth wiki.
4
+
5
+ https://github.com/omniauth/omniauth/wiki
6
+
7
+ The detail of the authentication middleware Shibboleth is introduced in Shibboleth wiki.
8
+
9
+ https://wiki.shibboleth.net/
10
+
11
+ OmniAuth basically works as a middleware of Rack applications. It provides environment variable named 'omniauth.auth' (auth hash) after authenticating a user. The 'auth hash' includes the user's attributes. By providing user attributes in the fixed format, applications can easily implement authentication function using multiple authentication methods.
12
+
13
+ OmniAuth Shibboleth strategy uses the 'auth hash' for providing user attributes passed by Shibboleth SP. It enables developers to use Shibboleth and the other authentication methods, including local auth, together in one application.
14
+
15
+ ## Getting Started
16
+
17
+ ### Install
18
+
19
+ gem 'omniauth-shibboleth-redux', require: 'omniauth-shibboleth'
20
+
21
+ ### Setup Shibboleth Strategy
22
+
23
+ To use OmniAuth Shibboleth strategy as a middleware in your rails application, add the following file to your rails application initializer directory.
24
+
25
+ % vi config/initializer/omniauth.rb
26
+ Rails.application.config.middleware.use OmniAuth::Builder do
27
+ provider :shibboleth
28
+ end
29
+
30
+ % vi config/initializer/omniauth.rb
31
+ Rails.application.config.middleware.use OmniAuth::Builder do
32
+ provider :shibboleth, {
33
+ :shib_session_id_field => "Shib-Session-ID",
34
+ :shib_application_id_field => "Shib-Application-ID",
35
+ :debug => false,
36
+ :extra_fields => [
37
+ :"unscoped-affiliation",
38
+ :entitlement
39
+ ]
40
+ }
41
+ end
42
+
43
+ In the above example, 'unscoped-affiliation' and 'entitlement' attributes are additionally provided in the raw_info field. They can be referred like request.env["omniauth.auth"]["extra"]["raw_info"]["unscoped-affiliation"]. The detail of the omniauth auth hash schema is described in the following page.
44
+
45
+ https://github.com/omniauth/omniauth/wiki/Auth-Hash-Schema
46
+
47
+ 'eppn' attribute is used as uid field. 'displayName' attribute is provided as request.env["omniauth.auth"]["info"]["name"].
48
+
49
+ These can be changed by :uid_field, :name_field option. You can also add any "info" fields defined in Auth-Hash-Schema by using :info_fields option.
50
+
51
+ % vi config/initializer/omniauth.rb
52
+ Rails.application.config.middleware.use OmniAuth::Builder do
53
+ provider :shibboleth, {
54
+ :uid_field => "uid",
55
+ :name_field => "displayName",
56
+ :info_fields => {
57
+ :email => "mail",
58
+ :location => "contactAddress",
59
+ :image => "photo_url",
60
+ :phone => "contactPhone"
61
+ }
62
+ }
63
+ end
64
+
65
+ In the previous example, Shibboleth strategy does not pass any :info fields and use 'uid' attribute as uid fields.
66
+
67
+ ### More flexible attribute configuration
68
+
69
+ If you need more flexible attribute definition, you can use lambda (Proc) to define your attributes. In the following example, 'uid' attribute is chosen from 'eppn' or 'mail', 'info'/'name' attribute is defined as a concatenation of 'cn' and 'sn' and 'info'/'affiliation' attribute is defined as 'affiliation'@my.localdomain. 'request_param' parameter is a method defined in OmniAuth::Shibboleth::Strategy. You can specify attribute names by downcase strings in either request_type, :env, :header and :params.
70
+
71
+ % vi config/initializer/omniauth.rb
72
+ Rails.application.config.middleware.use OmniAuth::Builder do
73
+ provider :shibboleth, {
74
+ :uid_field => lambda {|request_param| request_param.call('eppn') || request_param.call('mail')},
75
+ :name_field => lambda {|request_param| "#{request_param.call('cn')} #{request_param.call('sn')}"},
76
+ :info_fields => {
77
+ :affiliation => lambda {|request_param| "#{request_param.call('affiliation')}@my.localdomain"},
78
+ :email => "mail",
79
+ :location => "contactAddress",
80
+ :image => "photo_url",
81
+ :phone => "contactPhone"
82
+ }
83
+ }
84
+ end
85
+
86
+ ### !!!NOTICE!!! devise integration issue
87
+
88
+ When you use omniauth with devise, the omniauth configuration is applied before devise configuration and some part of the configuration overwritten by the devise's. It may not work as you assume. So thus, in that case, currently you should write your configuration only in device configuration.
89
+
90
+ config/initializers/devise.rb:
91
+ ```ruby
92
+ config.omniauth :shibboleth, {:uid_field => 'eppn',
93
+ :info_fields => {:email => 'mail', :name => 'cn', :last_name => 'sn'},
94
+ :extra_fields => [:schacHomeOrganization]
95
+ }
96
+ ```
97
+
98
+ The detail is discussed in the following thread.
99
+
100
+ https://github.com/plataformatec/devise/issues/2128
101
+
102
+
103
+ ### How to authenticate users
104
+
105
+ In your application, simply direct users to '/auth/shibboleth' to have them sign in via your company's Shibboleth SP and IdP. '/auth/shibboleth' url simply redirect users to '/auth/shibboleth/callback', so thus you must protect '/auth/shibboleth/callback' by Shibboleth SP.
106
+
107
+ Example shibd.conf:
108
+
109
+ <Location /application_path/auth/shibboleth/callback>
110
+ AuthType shibboleth
111
+ ShibRequestSetting requireSession 1
112
+ require valid-user
113
+ </Location>
114
+
115
+ Shibboleth strategy just checks the existence of Shib-Session-ID or Shib-Application-ID.
116
+
117
+ If you want to use omniauth-shibboleth-redux without Apache or IIS, you can try **rack-saml**. It supports a part of Shibboleth SP functions.
118
+
119
+ https://github.com/toyokazu/rack-saml
120
+
121
+ Shibboleth strategy assumes the attributes are provided via environment variables because the use of ShibUseHeaders option may cause some problems. The details are discussed in the following page:
122
+
123
+ https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPSpoofChecking
124
+
125
+ To provide Shibboleth attributes via environment variables, we can not use proxy based approach, e.g. mod_proxy_balancer. Currently we can realize it by using Phusion Passenger as an application container. An example construction pattern is shown in presence_checker application (https://github.com/toyokazu/presence_checker/).
126
+
127
+ ### :request_type option
128
+
129
+ You understand the issues using ShibUseHeaders, but and yet if you want to use the proxy based approach, you can use :request_type option. This option enables us to specify what kind of parameters are used to create 'omniauth.auth' (auth hash). This option can also be used to develop your Rails application without local IdP and SP by using :params option. The option values are:
130
+
131
+ - **:env** (default) The environment variables are used to create auth hash.
132
+ - **:header** The auth hash is created from header vaiables. In the Rack middleware, since header variables are treated as environment variables like HTTP_*, the specified variables are converted as the same as header variables, HTTP_*. This :request_type is basically used for mod_proxy_balancer approach.
133
+ - **:params** The query string or POST parameters are used to create auth hash. This :request_type is basically used for development phase. You can emulate SP function by providing parameters as query string. In this case, please do not forget to add Shib-Session-ID or Shib-Application-ID value which is used to check the session is created at SP.
134
+
135
+ The following is an example configuration.
136
+
137
+ % vi config/initializer/omniauth.rb
138
+ Rails.application.config.middleware.use OmniAuth::Builder do
139
+ provider :shibboleth, { :request_type => :header }
140
+ end
141
+
142
+ If you use proxy based approach, please be sure to add ShibUseHeaders option in mod_shib configuration.
143
+
144
+ <Location /secure>
145
+ AuthType shibboleth
146
+ ShibRequestSetting requireSession 1
147
+ ShibUseHeaders On
148
+ require valid-user
149
+ </Location>
150
+
151
+ ### debug mode
152
+
153
+ When you deploy a new application, you may want to confirm the assumed attributes are correctly provided by Shibboleth SP. OmniAuth Shibboleth strategy provides a confirmation option :debug. If you set :debug true, you can see the environment variables provided at the /auth/shibboleth/callback uri.
154
+
155
+ % vi config/initializer/omniauth.rb
156
+ Rails.application.config.middleware.use OmniAuth::Builder do
157
+ provider :shibboleth, { :debug => true }
158
+ end
159
+
160
+ ### :multi_values option
161
+
162
+ If your application want to receive multiple values as one attribute, Shibboleth passes them as follows:
163
+
164
+ user2@example2.com;user1@example1.com;user3@example3.com
165
+
166
+ If your application only wants the first entry sorted by alphabetical order, you can use flexible attribute configuration as follows (since semicolons in attribute values are escaped with a backslash, escaped semicolons are skiped for splitting):
167
+
168
+ % vi config/initializer/omniauth.rb
169
+ Rails.application.config.middleware.use OmniAuth::Builder do
170
+ provider :shibboleth, {
171
+ :info_fields => {
172
+ :email => lambda {|request_param| request_param.call('email').split(/(?<!\\);/).sort[0]}
173
+ }
174
+ }
175
+ end
176
+
177
+ However, if you use device to integrate omniauth, lambda function cannot be used. In such a situation, if you still think that attribute conversions in the middleware is required, you can use :multi_values option.
178
+
179
+ - **:raw** (default) Raw multiple values are passed to the application.
180
+ - **:first** The first entry of multiple values is passed to the application.
181
+ - **lambda function** The other descriptions are regarded as lambda function written in String form. The string will be evaluated as Ruby code and used for processing multiple values in the attribute.
182
+
183
+ If you specify :first, you can obtain `user2@example.com` in the above example.
184
+
185
+ % vi config/initializer/omniauth.rb
186
+ Rails.application.config.middleware.use OmniAuth::Builder do
187
+ provider :shibboleth, {
188
+ :multi_values => :first
189
+ }
190
+ end
191
+
192
+ If you need the first attribute in alphabetical order, you can specify lambda function in String form as follows:
193
+
194
+ % vi config/initializer/omniauth.rb
195
+ Rails.application.config.middleware.use OmniAuth::Builder do
196
+ provider :shibboleth, {
197
+ :multi_values => 'lambda {|param_value| param_value.nil? ? nil : param_value.split(/(?<!\\\\);/).sort[0]}'
198
+ }
199
+ end
200
+
201
+
202
+ ## License (MIT License)
203
+
204
+ omniauth-shibboleth-redux is released under the MIT license.
205
+
206
+ Permission is hereby granted, free of charge, to any person obtaining a copy
207
+ of this software and associated documentation files (the "Software"), to deal
208
+ in the Software without restriction, including without limitation the rights
209
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
210
+ copies of the Software, and to permit persons to whom the Software is
211
+ furnished to do so, subject to the following conditions:
212
+
213
+ The above copyright notice and this permission notice shall be included in
214
+ all copies or substantial portions of the Software.
215
+
216
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
217
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
218
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
219
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
220
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
221
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
222
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+ require "rspec/core/rake_task"
4
+ RSpec::Core::RakeTask.new("spec")
5
+ task :default => :spec
@@ -0,0 +1,109 @@
1
+ module OmniAuth
2
+ module Strategies
3
+ class Shibboleth
4
+ include OmniAuth::Strategy
5
+
6
+ option :shib_session_id_field, 'Shib-Session-ID'
7
+ option :shib_application_id_field, 'Shib-Application-ID'
8
+ option :uid_field, 'eppn'
9
+ option :name_field, 'displayName'
10
+ option :info_fields, {}
11
+ option :extra_fields, []
12
+ option :debug, false
13
+ option :fail_with_empty_uid, false
14
+ option :request_type, :env
15
+ option :multi_values, :raw
16
+
17
+ def request_phase
18
+ [
19
+ 302,
20
+ {
21
+ 'Location' => script_name + callback_path + query_string,
22
+ 'Content-Type' => 'text/plain'
23
+ },
24
+ ["You are being redirected to Shibboleth SP/IdP for sign-in."]
25
+ ]
26
+ end
27
+
28
+ def request_params
29
+ case options.request_type
30
+ when :env, 'env', :header, 'header'
31
+ request.env
32
+ when :params, 'params'
33
+ request.params
34
+ end
35
+ end
36
+
37
+ def request_param(key)
38
+ multi_value_handler(
39
+ case options.request_type
40
+ when :env, 'env'
41
+ request.env[key]
42
+ when :header, 'header'
43
+ request.env["HTTP_#{key.upcase.gsub('-', '_')}"]
44
+ when :params, 'params'
45
+ request.params[key]
46
+ end
47
+ )
48
+ end
49
+
50
+ def multi_value_handler(param_value)
51
+ case options.multi_values
52
+ when :raw, 'raw'
53
+ param_value
54
+ when :first, 'first'
55
+ return nil if param_value.nil?
56
+ param_value.split(/(?<!\\);/).first.gsub('\\;', ';')
57
+ else
58
+ eval(options.multi_values).call(param_value)
59
+ end
60
+ end
61
+
62
+ def callback_phase
63
+ if options.debug
64
+ # dump attributes
65
+ return [
66
+ 200,
67
+ {
68
+ 'Content-Type' => 'text/plain'
69
+ },
70
+ ["!!!!! This message is generated by omniauth-shibboleth. To remove it set :debug to false. !!!!!\n#{request_params.sort.map {|i| "#{i[0]}: #{i[1]}" }.join("\n")}"]
71
+ ]
72
+ end
73
+ return fail!(:no_shibboleth_session) unless (request_param(options.shib_session_id_field.to_s) || request_param(options.shib_application_id_field.to_s))
74
+ return fail!(:empty_uid) if options.fail_with_empty_uid && option_handler(options.uid_field).empty?
75
+ super
76
+ end
77
+
78
+ def option_handler(option_field)
79
+ if option_field.class == String ||
80
+ option_field.class == Symbol
81
+ request_param(option_field.to_s)
82
+ elsif option_field.class == Proc
83
+ option_field.call(self.method(:request_param))
84
+ end
85
+ end
86
+
87
+ uid do
88
+ option_handler(options.uid_field)
89
+ end
90
+
91
+ info do
92
+ res = {
93
+ :name => option_handler(options.name_field)
94
+ }
95
+ options.info_fields.each_pair do |key, field|
96
+ res[key] = option_handler(field)
97
+ end
98
+ res
99
+ end
100
+
101
+ extra do
102
+ options.extra_fields.inject({:raw_info => {}}) do |hash, field|
103
+ hash[:raw_info][field] = request_param(field.to_s)
104
+ hash
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,5 @@
1
+ module OmniAuth
2
+ module Shibboleth
3
+ VERSION = "2.0.0"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require "omniauth-shibboleth/version"
2
+ require "omniauth"
3
+
4
+ module OmniAuth
5
+ module Strategies
6
+ autoload :Shibboleth, 'omniauth/strategies/shibboleth'
7
+ end
8
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/omniauth-shibboleth/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.add_dependency 'omniauth', '>= 2.0.0'
6
+
7
+ gem.add_development_dependency 'rack-test'
8
+ gem.add_development_dependency 'rack-session'
9
+ gem.add_development_dependency 'rake'
10
+ gem.add_development_dependency 'rspec', '>= 2.8'
11
+
12
+ gem.license = 'MIT'
13
+
14
+ gem.authors = ["Bobby McDonald", "Toyokazu Akiyama"]
15
+ gem.email = ["bobbymcwho@gmail.com", "toyokazu@gmail.com"]
16
+ gem.description = %q{OmniAuth Shibboleth strategies for OmniAuth 2.x}
17
+ gem.summary = %q{OmniAuth Shibboleth strategies for OmniAuth 2.x}
18
+ gem.homepage = ""
19
+
20
+ gem.files = `find . -not \\( -regex ".*\\.git.*" -o -regex "\\./pkg.*" -o -regex "\\./spec.*" \\)`.split("\n").map{ |f| f.gsub(/^.\//, '') }
21
+ gem.test_files = `find spec/*`.split("\n")
22
+ gem.name = "omniauth-shibboleth-redux"
23
+ gem.require_paths = ["lib"]
24
+ gem.version = OmniAuth::Shibboleth::VERSION
25
+
26
+
27
+ end
@@ -0,0 +1,358 @@
1
+ #require 'pry-byebug'
2
+ require 'spec_helper'
3
+ require 'rack/session'
4
+
5
+ def make_env(path = '/auth/shibboleth', props = {})
6
+ {
7
+ 'REQUEST_METHOD' => 'GET',
8
+ 'PATH_INFO' => path,
9
+ 'rack.session' => {},
10
+ 'rack.input' => StringIO.new('test=true')
11
+ }.merge(props)
12
+ end
13
+
14
+ def without_session_failure_path
15
+ "/auth/failure?message=no_shibboleth_session&strategy=shibboleth"
16
+ end
17
+
18
+ def empty_uid_failure_path
19
+ "/auth/failure?message=empty_uid&strategy=shibboleth"
20
+ end
21
+
22
+ describe OmniAuth::Strategies::Shibboleth do
23
+ let(:app){ Rack::Builder.new do |b|
24
+ b.use Rack::Session::Cookie, {:secret => SecureRandom.hex(64) }
25
+ b.use OmniAuth::Strategies::Shibboleth
26
+ b.run lambda{|env| [200, {}, ['Not Found']]}
27
+ end.to_app }
28
+
29
+ before do
30
+ OmniAuth.config.request_validation_phase = ->(_env) { true }
31
+ end
32
+
33
+ context 'request phase' do
34
+ before do
35
+ post '/auth/shibboleth'
36
+ end
37
+
38
+ it 'is expected to redirect to callback_url' do
39
+ expect(last_response.status).to eq(302)
40
+ expect(last_response.location).to eq('/auth/shibboleth/callback')
41
+ end
42
+ end
43
+
44
+ context 'callback phase' do
45
+ context 'without Shibboleth session' do
46
+ before do
47
+ get '/auth/shibboleth/callback'
48
+ end
49
+
50
+ it 'is expected to fail to get Shib-Session-ID environment variable' do
51
+ expect(last_response.status).to eq(302)
52
+ expect(last_response.location).to eq(without_session_failure_path)
53
+ end
54
+ end
55
+
56
+ context 'with Shibboleth session' do
57
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, {}) }
58
+
59
+ it 'is expected to set default omniauth.auth fields' do
60
+ @dummy_id = 'abcdefg'
61
+ @eppn = 'test@example.com'
62
+ @display_name = 'Test User'
63
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'eppn' => @eppn, 'displayName' => @display_name)
64
+ strategy.call!(env)
65
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@eppn)
66
+ expect(strategy.env['omniauth.auth']['info']['name']).to eq(@display_name)
67
+ end
68
+ end
69
+
70
+ context 'with Shibboleth session and attribute options' do
71
+ let(:options){ {
72
+ :shib_session_id_field => 'Shib-Session-ID',
73
+ :shib_application_id_field => 'Shib-Application-ID',
74
+ :uid_field => :uid,
75
+ :name_field => :sn,
76
+ :info_fields => {},
77
+ :extra_fields => [:o, :affiliation] } }
78
+ let(:app){ lambda{|env| [404, {}, ['Not Found']]}}
79
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
80
+
81
+ it 'is expected to set specified omniauth.auth fields' do
82
+ @dummy_id = 'abcdefg'
83
+ @uid = 'test'
84
+ @sn = 'User'
85
+ @organization = 'Test Corporation'
86
+ @affiliation = 'faculty'
87
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'uid' => @uid, 'sn' => @sn, 'o' => @organization, 'affiliation' => @affiliation)
88
+ strategy.call!(env)
89
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@uid)
90
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['o']).to eq(@organization)
91
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['affiliation']).to eq(@affiliation)
92
+ end
93
+ end
94
+
95
+ context 'with debug options' do
96
+ let(:options) { { :debug => true } }
97
+ let(:app){ lambda{|env| [404, {}, ['Not Found']]}}
98
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
99
+
100
+ it 'is expected to raise environment variables' do
101
+ @dummy_id = 'abcdefg'
102
+ @eppn = 'test@example.com'
103
+ @display_name = 'Test User'
104
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'eppn' => @eppn, 'displayName' => @display_name)
105
+ response = strategy.call!(env)
106
+ expect(response[0]).to eq(200)
107
+ end
108
+ end
109
+
110
+ context 'with request_type = :header' do
111
+ let(:options){ {
112
+ :request_type => :header,
113
+ :shib_session_id_field => 'Shib-Session-ID',
114
+ :shib_application_id_field => 'Shib-Application-ID',
115
+ :uid_field => :uid,
116
+ :name_field => :displayName,
117
+ :info_fields => {},
118
+ :extra_fields => [:o, :affiliation] } }
119
+ let(:app){ lambda{|env| [200, {}, ['OK']]}}
120
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
121
+
122
+ it 'is expected to handle header variables' do
123
+ @dummy_id = 'abcdefg'
124
+ @display_name = 'Test User'
125
+ @uid = 'test'
126
+ @organization = 'Test Corporation'
127
+ @affiliation = 'faculty'
128
+ env = make_env('/auth/shibboleth/callback', 'HTTP_SHIB_SESSION_ID' => @dummy_id, 'HTTP_DISPLAYNAME' => @display_name, 'HTTP_UID' => @uid, 'HTTP_O' => @organization, 'HTTP_AFFILIATION' => @affiliation)
129
+ strategy.call!(env)
130
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@uid)
131
+ expect(strategy.env['omniauth.auth']['info']['name']).to eq(@display_name)
132
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['o']).to eq(@organization)
133
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['affiliation']).to eq(@affiliation)
134
+ end
135
+ end
136
+
137
+ context "with request_type = 'header'" do
138
+ let(:options){ {
139
+ :request_type => 'header',
140
+ :shib_session_id_field => 'Shib-Session-ID',
141
+ :shib_application_id_field => 'Shib-Application-ID',
142
+ :uid_field => :uid,
143
+ :name_field => :displayName,
144
+ :info_fields => {},
145
+ :extra_fields => [:o, :affiliation] } }
146
+ let(:app){ lambda{|env| [200, {}, ['OK']]}}
147
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
148
+
149
+ it 'is expected to handle header variables' do
150
+ @dummy_id = 'abcdefg'
151
+ @display_name = 'Test User'
152
+ @uid = 'test'
153
+ @organization = 'Test Corporation'
154
+ @affiliation = 'faculty'
155
+ env = make_env('/auth/shibboleth/callback', 'HTTP_SHIB_SESSION_ID' => @dummy_id, 'HTTP_DISPLAYNAME' => @display_name, 'HTTP_UID' => @uid, 'HTTP_O' => @organization, 'HTTP_AFFILIATION' => @affiliation)
156
+ strategy.call!(env)
157
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@uid)
158
+ expect(strategy.env['omniauth.auth']['info']['name']).to eq(@display_name)
159
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['o']).to eq(@organization)
160
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['affiliation']).to eq(@affiliation)
161
+ end
162
+ end
163
+
164
+ context 'with request_type = :params' do
165
+ let(:options){ {
166
+ :request_type => :params,
167
+ :shib_session_id_field => 'Shib-Session-ID',
168
+ :shib_application_id_field => 'Shib-Application-ID',
169
+ :uid_field => :uid,
170
+ :name_field => :displayName,
171
+ :info_fields => {},
172
+ :extra_fields => [:o, :affiliation] } }
173
+ let(:app){ lambda{|env| [200, {}, ['OK']]}}
174
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
175
+
176
+ it 'is expected to handle params variables' do
177
+ @dummy_id = 'abcdefg'
178
+ @display_name = 'Test User'
179
+ @uid = 'test'
180
+ @organization = 'Test Corporation'
181
+ @affiliation = 'faculty'
182
+ env = make_env('/auth/shibboleth/callback', 'QUERY_STRING' => "Shib-Session-ID=#{@dummy_id}&uid=#{@uid}&displayName=#{@display_name}&o=#{@organization}&affiliation=#{@affiliation}")
183
+ strategy.call!(env)
184
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@uid)
185
+ expect(strategy.env['omniauth.auth']['info']['name']).to eq(@display_name)
186
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['o']).to eq(@organization)
187
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['affiliation']).to eq(@affiliation)
188
+ end
189
+ end
190
+
191
+ context 'with Proc option' do
192
+ let(:options){ {
193
+ :request_type => :env,
194
+ :shib_session_id_field => 'Shib-Session-ID',
195
+ :shib_application_id_field => 'Shib-Application-ID',
196
+ :uid_field => lambda {|request_param| request_param.call('eppn') || request_param.call('mail')},
197
+ :name_field => lambda {|request_param| "#{request_param.call('cn')} #{request_param.call('sn')}"},
198
+ :info_fields => {:affiliation => lambda {|request_param| "#{request_param.call('affiliation')}@my.localdomain" }},
199
+ :extra_fields => [:o, :affiliation] } }
200
+ let(:app){ lambda{|env| [200, {}, ['OK']]}}
201
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
202
+
203
+ it 'is expected to have eppn as uid and cn + sn as name field.' do
204
+ @dummy_id = 'abcdefg'
205
+ @display_name = 'Test User'
206
+ @uid = 'test'
207
+ @eppn = 'test@my.localdomain'
208
+ @cn = 'Test'
209
+ @sn = 'User'
210
+ @organization = 'Test Corporation'
211
+ @affiliation = 'faculty'
212
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'uid' => @uid, 'eppn' => @eppn, 'cn' => @cn, 'sn' => @sn, 'o' => @organization, 'affiliation' => @affiliation)
213
+ strategy.call!(env)
214
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@eppn)
215
+ expect(strategy.env['omniauth.auth']['info']['name']).to eq("#{@cn} #{@sn}")
216
+ expect(strategy.env['omniauth.auth']['info']['affiliation']).to eq("#{@affiliation}@my.localdomain")
217
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['o']).to eq(@organization)
218
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['affiliation']).to eq(@affiliation)
219
+ end
220
+
221
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
222
+ it 'is expected to have mail as uid and cn + sn as name field.' do
223
+ @dummy_id = 'abcdefg'
224
+ @display_name = 'Test User'
225
+ @uid = 'test'
226
+ @mail = 'test@my.localdomain'
227
+ @cn = 'Test'
228
+ @sn = 'User'
229
+ @organization = 'Test Corporation'
230
+ @affiliation = 'faculty'
231
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'uid' => @uid, 'mail' => @mail, 'cn' => @cn, 'sn' => @sn, 'o' => @organization, 'affiliation' => @affiliation)
232
+ strategy.call!(env)
233
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@mail)
234
+ expect(strategy.env['omniauth.auth']['info']['name']).to eq("#{@cn} #{@sn}")
235
+ expect(strategy.env['omniauth.auth']['info']['affiliation']).to eq("#{@affiliation}@my.localdomain")
236
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['o']).to eq(@organization)
237
+ expect(strategy.env['omniauth.auth']['extra']['raw_info']['affiliation']).to eq(@affiliation)
238
+ end
239
+ end
240
+
241
+ context 'empty uid with :fail_with_empty_uid = false' do
242
+ let(:options){ {
243
+ :request_type => :env,
244
+ :fail_with_empty_uid => false,
245
+ :uid_field => :uid,
246
+ :name_field => :displayName,
247
+ :info_fields => {} } }
248
+ let(:app){ lambda{|env| [200, {}, ['OK']]}}
249
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
250
+
251
+ it 'is expected to output null (empty) uid as it is' do
252
+ @dummy_id = 'abcdefg'
253
+ @display_name = 'Test User'
254
+ @uid = ''
255
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'uid' => @uid, 'displayName' => @display_name)
256
+ strategy.call!(env)
257
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@uid)
258
+ end
259
+ end
260
+
261
+ context 'empty uid with :fail_with_empty_uid = true' do
262
+ let(:options){ {
263
+ :request_type => :env,
264
+ :fail_with_empty_uid => true,
265
+ :shib_session_id_field => 'Shib-Session-ID',
266
+ :shib_application_id_field => 'Shib-Application-ID',
267
+ :uid_field => :uid,
268
+ :name_field => :displayName,
269
+ :info_fields => {} } }
270
+ let(:app){ lambda{|env| [200, {}, ['OK']]}}
271
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
272
+
273
+ it 'is expected to fail because of the empty uid' do
274
+ @dummy_id = 'abcdefg'
275
+ @display_name = 'Test User'
276
+ @uid = ''
277
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'uid' => @uid, 'displayName' => @display_name)
278
+ response = strategy.call!(env)
279
+ expect(response[0]).to eq(302)
280
+ expect(response[1]["Location"]).to eq(empty_uid_failure_path)
281
+ end
282
+ end
283
+
284
+ context 'with :multi_values => :raw' do
285
+ let(:options){ {
286
+ :request_type => :env,
287
+ :shib_session_id_field => 'Shib-Session-ID',
288
+ :shib_application_id_field => 'Shib-Application-ID',
289
+ :uid_field => :uid,
290
+ :name_field => :displayName,
291
+ :info_fields => {:email => "mail"} } }
292
+ let(:app){ lambda{|env| [200, {}, ['OK']]}}
293
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
294
+
295
+ it 'is expected to return the raw value' do
296
+ @dummy_id = 'abcdefg'
297
+ @display_name = 'Test User'
298
+ @uid = 'test'
299
+ @mail = 'test2\;hoge@example.com;test1\;hoge@example.com;test3\;hoge@example.com'
300
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'uid' => @uid, 'displayName' => @display_name, 'mail' => @mail)
301
+ strategy.call!(env)
302
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@uid)
303
+ expect(strategy.env['omniauth.auth']['info']['name']).to eq(@display_name)
304
+ expect(strategy.env['omniauth.auth']['info']['email']).to eq(@mail)
305
+ end
306
+ end
307
+
308
+ context 'with :multi_values => :first' do
309
+ let(:options){ {
310
+ :multi_values => :first,
311
+ :request_type => :env,
312
+ :shib_session_id_field => 'Shib-Session-ID',
313
+ :shib_application_id_field => 'Shib-Application-ID',
314
+ :uid_field => :uid,
315
+ :name_field => :displayName,
316
+ :info_fields => {:email => "mail"} } }
317
+ let(:app){ lambda{|env| [200, {}, ['OK']]}}
318
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
319
+
320
+ it 'is expected return the first value by specifying :first' do
321
+ @dummy_id = 'abcdefg'
322
+ @display_name = 'Test User'
323
+ @uid = 'test'
324
+ @mail = 'test2\;hoge@example.com;test1\;hoge@example.com;test3\;hoge@example.com'
325
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'uid' => @uid, 'displayName' => @display_name, 'mail' => @mail)
326
+ strategy.call!(env)
327
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@uid)
328
+ expect(strategy.env['omniauth.auth']['info']['name']).to eq(@display_name)
329
+ expect(strategy.env['omniauth.auth']['info']['email']).to eq('test2;hoge@example.com')
330
+ end
331
+ end
332
+
333
+ context 'with :multi_values => lambda function' do
334
+ let(:options){ {
335
+ :multi_values => "lambda {|param_value| param_value.nil? ? nil : param_value.split(/(?<!\\\\);/).sort[0].gsub('\\;',';')}",
336
+ :request_type => :env,
337
+ :shib_session_id_field => 'Shib-Session-ID',
338
+ :shib_application_id_field => 'Shib-Application-ID',
339
+ :uid_field => :uid,
340
+ :name_field => :displayName,
341
+ :info_fields => {:email => "mail"} } }
342
+ let(:app){ lambda{|env| [200, {}, ['OK']]}}
343
+ let(:strategy){ OmniAuth::Strategies::Shibboleth.new(app, options) }
344
+ it 'is expected return the processed value by specifying lambda function' do
345
+ @dummy_id = 'abcdefg'
346
+ @display_name = 'Test User'
347
+ @uid = 'test'
348
+ @mail = 'test2\;hoge@example.com;test1\;hoge@example.com;test3\;hoge@example.com'
349
+ env = make_env('/auth/shibboleth/callback', 'Shib-Session-ID' => @dummy_id, 'uid' => @uid, 'displayName' => @display_name, 'mail' => @mail)
350
+ strategy.call!(env)
351
+ expect(strategy.env['omniauth.auth']['uid']).to eq(@uid)
352
+ expect(strategy.env['omniauth.auth']['info']['name']).to eq(@display_name)
353
+ expect(strategy.env['omniauth.auth']['info']['email']).to eq('test1;hoge@example.com')
354
+ end
355
+ end
356
+
357
+ end
358
+ end
@@ -0,0 +1,10 @@
1
+ require 'rspec'
2
+ require 'rack/test'
3
+ require 'omniauth'
4
+ require 'omniauth/version'
5
+ require 'omniauth-shibboleth'
6
+
7
+ RSpec.configure do |config|
8
+ config.include Rack::Test::Methods
9
+ config.color = true
10
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omniauth-shibboleth-redux
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Bobby McDonald
8
+ - Toyokazu Akiyama
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2023-03-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: omniauth
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 2.0.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 2.0.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: rack-test
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rack-session
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '2.8'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '2.8'
84
+ description: OmniAuth Shibboleth strategies for OmniAuth 2.x
85
+ email:
86
+ - bobbymcwho@gmail.com
87
+ - toyokazu@gmail.com
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - Gemfile
93
+ - Gemfile.lock
94
+ - README.md
95
+ - Rakefile
96
+ - lib/omniauth-shibboleth.rb
97
+ - lib/omniauth-shibboleth/version.rb
98
+ - lib/omniauth/strategies/shibboleth.rb
99
+ - omniauth-shibboleth.gemspec
100
+ - spec/omniauth/strategies/shibboleth_spec.rb
101
+ - spec/spec_helper.rb
102
+ homepage: ''
103
+ licenses:
104
+ - MIT
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubygems_version: 3.2.32
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: OmniAuth Shibboleth strategies for OmniAuth 2.x
125
+ test_files:
126
+ - spec/omniauth/strategies/shibboleth_spec.rb
127
+ - spec/spec_helper.rb