omniauth-signicat 1.6.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
+ SHA1:
3
+ metadata.gz: fc291d34932e5333c40e4a218590e1fd0bcbd495
4
+ data.tar.gz: 2e38e29be4badafe083aff0a0b88e59eaad7c4a3
5
+ SHA512:
6
+ metadata.gz: cd0c52f433b28da51137d841fea1b0358e9d578df8196e909dba5940dd49ca1ff9f1bdd66679a7e324c2f16d95239a5082e1030e710f70e395967c42466e3bce
7
+ data.tar.gz: cb0c5ea48e377b56cecba069b7cc1fc008658435858d155ecb1787636de9a984cff4dbaa49ba7faf8e594c7f226de9040c6ff78929e819e8ced39dc9ee34877d
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # OmniAuth Signicat Version History
2
+
3
+ A Signicat strategy for OmniAuth.
4
+
5
+ https://github.com/Nabobil/omniauth-signicat
6
+
7
+ ## 1.6.0 (2016-05-16)
8
+
9
+ * First version
10
+
11
+ ## 1.5.0 and prior
12
+
13
+ * Please view the [OmniAuth SAML project](https://github.com/omniauth/omniauth-saml)
data/LICENSE.md ADDED
@@ -0,0 +1,25 @@
1
+ # License
2
+
3
+ Copyright © 2016 Omniauth-SAML maintainers
4
+
5
+ Copyright © 2011-2014 [Practically Green, Inc.](http://www.practicallygreen.com/).
6
+
7
+ All rights reserved. Released under the MIT license.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in
17
+ all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # OmniAuth Signicat
2
+
3
+ [![Gem Version](http://img.shields.io/gem/v/omniauth-signicat.svg)][gem]
4
+ [![Build Status](https://img.shields.io/codeship/10a7cb50-af95-0132-a853-0e5ba92aabbb.svg)][codeship]
5
+ [![Dependency Status](http://img.shields.io/gemnasium/Nabobil/omniauth-signicat.svg)][gemnasium]
6
+ [![Coverage Status](http://img.shields.io/coveralls/Nabobil/omniauth-signicat.svg)][coveralls]
7
+
8
+ [gem]: https://rubygems.org/gems/omniauth-signicat
9
+ [codeship]: https://codeship.com/projects/152234
10
+ [gemnasium]: https://gemnasium.com/github.com/Nabobil/omniauth-signicat
11
+ [coveralls]: https://coveralls.io/github/Nabobil/omniauth-signicat
12
+
13
+ Signicat strategy for OmniAuth available under the [MIT License](LICENSE.md)
14
+
15
+ https://github.com/Nabobil/omniauth-signicat
16
+
17
+ ## Requirements
18
+
19
+ * [OmniAuth](http://www.omniauth.org/) 1.3+
20
+ * Ruby 1.9.x or Ruby 2.1.x+
21
+
22
+ ## Versioning
23
+
24
+ We tag and release gems according to the [Semantic Versioning](http://semver.org/) principle.
25
+
26
+ ## Usage
27
+
28
+ Use the Signicat strategy as a middleware in your application:
29
+
30
+ ```ruby
31
+ require 'omniauth'
32
+ use OmniAuth::Strategies::Signicat,
33
+ :env => 'preprod',
34
+ :service => 'demo',
35
+ :method => 'nbid',
36
+ :language => 'nb'
37
+ ```
38
+
39
+ or in your Rails application:
40
+
41
+ in `Gemfile`:
42
+
43
+ ```ruby
44
+ gem 'omniauth-signicat'
45
+ ```
46
+
47
+ and in `config/initializers/omniauth.rb`:
48
+
49
+ ```ruby
50
+ Rails.application.config.middleware.use OmniAuth::Builder do
51
+ provider :signicat,
52
+ :env => 'preprod',
53
+ :service => 'demo',
54
+ :method => 'nbid',
55
+ :language => 'nb'
56
+ end
57
+ ```
58
+
59
+ ## Options
60
+
61
+ * `:env` - `preprod` or `id`. **Required**.
62
+
63
+ * `:service` - The name of your service as registered with Signicat. There is a
64
+ demo preprod service called `demo` which you may use as you'd like, but eventually
65
+ you will start using your own service. **Required**.
66
+
67
+ * `:method` - The name of the id-method as registered with Signicat. Common
68
+ abbreviations are `nbid` for Norwegian BankID, `sbid` for Swedish BankID,
69
+ `nemid` for Danish NemID, `tupas` for Finnish Tupas, `esteid` for Estonian
70
+ ID-card and so on. **Required**.
71
+
72
+ * `:language` - Two letter code (ISO 639-1) for the language you would like in
73
+ the user interface, such as `nb` for Norwegian, `da` for Danish, `sv` for
74
+ Swedish, `fi` for Finnish, `et` for Estonian and so on. **Required**.
75
+
76
+ * `:profile` - The name of the graphical profile you would like to use. If you
77
+ don't have a graphical profile, you can omit the value and the default profile
78
+ will be used. Optional.
79
+
80
+ ## Devise Integration
81
+
82
+ Straightforward integration with [Devise](https://github.com/plataformatec/devise), the widely-used authentication solution for Rails.
83
+
84
+ In `config/initializers/devise.rb`:
85
+
86
+ ```ruby
87
+ Devise.setup do |config|
88
+ config.omniauth :signicat,
89
+ :env => 'preprod',
90
+ :service => 'demo',
91
+ :method => 'nbid',
92
+ :language => 'nb'
93
+ end
94
+ ```
95
+
96
+ Then follow Devise's general [OmniAuth tutorial](https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview), replacing references to `facebook` with `signicat`.
97
+
98
+ ## Authors
99
+
100
+ Authored by [Theodor Tonum](https://github.com/theodorton) at [Nabobil](https://nabobil.no).
101
+
102
+ Original `omniauth-saml` project authored by [Rajiv Aaron Manglani](http://www.rajivmanglani.com/), Raecoo Cao, Todd W Saxton, Ryan Wilcox, Steven Anderson, Nikos Dimitrakopoulos, Rudolf Vriend and [Bruno Pedro](http://brunopedro.com/).
@@ -0,0 +1,2 @@
1
+ require 'omniauth/strategies/signicat'
2
+ require 'omniauth/strategies/signicat/validation_error'
@@ -0,0 +1,5 @@
1
+ module OmniAuth
2
+ module Signicat
3
+ VERSION = '1.6.0'.freeze
4
+ end
5
+ end
@@ -0,0 +1,118 @@
1
+ require 'omniauth'
2
+ require 'cgi'
3
+ require 'base64'
4
+ require 'nokogiri'
5
+ require 'digest/sha1'
6
+
7
+ module OmniAuth
8
+ module Strategies
9
+ # OmniAuth Strategy for authenticating with Signicat based identity solutions
10
+ class Signicat
11
+ include OmniAuth::Strategy
12
+
13
+ def self.inherited(subclass)
14
+ OmniAuth::Strategy.included(subclass)
15
+ end
16
+
17
+ XML_DS_NS = 'http://www.w3.org/2000/09/xmldsig#'.freeze
18
+
19
+ option :env, 'preprod'
20
+ option :service, 'demo'
21
+ option :method, nil
22
+ option :profile, 'default'
23
+ option :language, 'en'
24
+
25
+ def request_phase
26
+ redirect(target_url)
27
+ end
28
+
29
+ def callback_phase
30
+ unless request.params['SAMLResponse']
31
+ raise OmniAuth::Strategies::Signicat::ValidationError, 'SAML response missing'
32
+ end
33
+
34
+ saml_response = Base64.decode64(request.params['SAMLResponse'])
35
+ xml = Nokogiri.parse(saml_response)
36
+ verify_signature!(xml)
37
+ assign_attributes(xml)
38
+
39
+ super
40
+ rescue OmniAuth::Strategies::Signicat::ValidationError
41
+ fail!(:invalid_ticket, $ERROR_INFO)
42
+ end
43
+
44
+ def target_url
45
+ [
46
+ "https://#{options[:env]}.signicat.com",
47
+ "/std/method/#{options[:service]}",
48
+ "?id=#{options[:method]}:#{options[:profile]}:#{options[:language]}",
49
+ "&target=#{CGI.escape(callback_url)}"
50
+ ].join('')
51
+ end
52
+
53
+ uid { @name_id }
54
+
55
+ info do
56
+ {
57
+ 'firstname' => @attributes['firstname'],
58
+ 'lastname' => @attributes['lastname'],
59
+ 'date-of-birth' => @attributes['date-of-birth']
60
+ }
61
+ end
62
+
63
+ extra { { raw_info: @attributes } }
64
+
65
+ private
66
+
67
+ def verify_signature!(xml)
68
+ key = extract_public_key(xml)
69
+
70
+ signed_info = extract_signed_info(xml)
71
+ signature = extract_signature(xml)
72
+ return if key.verify(OpenSSL::Digest::SHA1.new, signature, signed_info)
73
+
74
+ raise OmniAuth::Strategies::Signicat::ValidationError, 'Invalid signature'
75
+ end
76
+
77
+ def extract_public_key(xml)
78
+ raw_cert = xml.xpath('//ds:X509Certificate/text()', 'ds' => XML_DS_NS).text
79
+ cert = OpenSSL::X509::Certificate.new(Base64.decode64(raw_cert))
80
+ if cert.subject.to_s != expected_cert_subject
81
+ raise OmniAuth::Strategies::Signicat::ValidationError, 'Invalid certificate'
82
+ end
83
+ cert.public_key
84
+ end
85
+
86
+ def extract_signed_info(xml)
87
+ noko_sig_element = xml.at_xpath('//ds:Signature', 'ds' => XML_DS_NS)
88
+ noko_signed_info_element = noko_sig_element.at_xpath('./ds:SignedInfo', 'ds' => XML_DS_NS)
89
+
90
+ canon_algorithm = Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
91
+ noko_signed_info_element.canonicalize(canon_algorithm)
92
+ end
93
+
94
+ def extract_signature(xml)
95
+ raw_signature = xml.xpath('//ds:SignatureValue', 'ds' => XML_DS_NS).text
96
+ Base64.decode64(raw_signature)
97
+ end
98
+
99
+ def assign_attributes(xml)
100
+ @attributes = {}
101
+ xml.xpath('//saml:Attribute').each do |attr_node|
102
+ key = attr_node['AttributeName']
103
+ value = attr_node.text
104
+ @attributes[key] = value
105
+ end
106
+ @name_id = @attributes['unique-id']
107
+ end
108
+
109
+ def expected_cert_subject
110
+ if options[:env] == 'id'
111
+ '/C=NO/ST=Norway/L=Trondheim/O=Signicat/OU=Signicat/CN=id.signicat.com/std'
112
+ else
113
+ '/C=NO/ST=Norway/L=Trondheim/O=Signicat/OU=Signicat/CN=test.signicat.com/std'
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,8 @@
1
+ module OmniAuth
2
+ module Strategies
3
+ class Signicat
4
+ class ValidationError < RuntimeError
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,140 @@
1
+ # rubocop:disable Metrics/LineLength
2
+ require 'spec_helper'
3
+
4
+ RSpec::Matchers.define :fail_with do |message|
5
+ match do |actual|
6
+ actual.redirect? && /\?.*message=#{message}/ =~ actual.location
7
+ end
8
+ end
9
+
10
+ def post_xml(xml = :example_response)
11
+ post '/auth/signicat/callback', 'SAMLResponse' => load_xml(xml)
12
+ end
13
+
14
+ describe OmniAuth::Strategies::Signicat, type: :strategy do
15
+ include OmniAuth::Test::StrategyTestCase
16
+
17
+ let(:auth_hash) { last_request.env['omniauth.auth'] }
18
+ let(:signicat_options) do
19
+ {
20
+ env: 'preprod',
21
+ service: 'demo',
22
+ method: 'nbid',
23
+ language: 'nb'
24
+ }
25
+ end
26
+ let(:strategy) { [OmniAuth::Strategies::Signicat, signicat_options] }
27
+
28
+ describe 'GET /auth/signicat' do
29
+ before do
30
+ get '/auth/signicat'
31
+ end
32
+
33
+ it 'should redirect correctly' do
34
+ last_response.location.should include 'https://preprod.signicat.com/std/method/demo?id=nbid:default:nb'
35
+ end
36
+ end
37
+
38
+ describe 'POST /auth/signicat/callback' do
39
+ subject { last_response }
40
+
41
+ let(:xml) { :example_response }
42
+
43
+ before :each do
44
+ Time.stub(:now).and_return(Time.utc(2016, 5, 10, 8, 57, 00))
45
+ end
46
+
47
+ shared_examples_for 'a valid response' do
48
+ it 'should set the uid to the nameID in the SAML response' do
49
+ auth_hash['uid'].should == '9578-6000-4-140135'
50
+ end
51
+
52
+ it 'should set the info' do
53
+ auth_hash[:info].should == {
54
+ 'firstname' => 'Bjørn Test',
55
+ 'lastname' => 'Teisvær',
56
+ 'date-of-birth' => '1961-03-23'
57
+ }
58
+ end
59
+
60
+ it 'should set the raw info to all attributes' do
61
+ auth_hash['extra'][:raw_info].should == {
62
+ 'action' => 'auth',
63
+ 'bank' => 'TestBank1',
64
+ 'bankid-no' => '9578-6000-4-140135',
65
+ 'date-of-birth' => '1961-03-23',
66
+ 'firstname' => "Bjørn Test",
67
+ 'fnr' => '23036107340',
68
+ 'issuer-dn' => 'CN=BankID TestBank1 Bank CA 2,OU=123456789,O=TestBank1 AS,C=NO',
69
+ 'key-algorithm' => 'RSA',
70
+ 'key-size' => '2048',
71
+ 'lastname' => "Teisvær",
72
+ 'method-name' => 'nbid',
73
+ 'monetary-limit-amount' => '100000',
74
+ 'monetary-limit-currency' => 'NOK',
75
+ 'national-id' => '23036107340',
76
+ 'no.fnr' => '23036107340',
77
+ 'originator' => '9999',
78
+ 'plain-name' => "Teisvær, Bjørn Test",
79
+ 'policy-oid' => '2.16.578.1.16.1.12.1.1',
80
+ 'qualified' => 'true',
81
+ 'security-level' => '3',
82
+ 'serialnumber' => '552735',
83
+ 'service-name' => 'shared',
84
+ 'subject-dn' => "CN=Teisvær\\, Bjørn Test,O=BankID - TestBank1,C=NO,SERIALNUMBER=9578-6000-4-140135",
85
+ 'unique-id' => '9578-6000-4-140135',
86
+ 'valid-from' => '2016-05-09',
87
+ 'valid-to' => '2018-05-09',
88
+ 'version-number' => '3'
89
+ }
90
+ end
91
+ end
92
+
93
+ context 'when the response is valid' do
94
+ before :each do
95
+ post_xml
96
+ end
97
+
98
+ it_behaves_like 'a valid response'
99
+ end
100
+
101
+ context 'when there is no SAMLResponse parameter' do
102
+ before :each do
103
+ post '/auth/signicat/callback'
104
+ end
105
+
106
+ it { should fail_with(:invalid_ticket) }
107
+ end
108
+
109
+ context 'when the digest is invalid' do
110
+ before :each do
111
+ post_xml :digest_mismatch
112
+ end
113
+
114
+ it { should fail_with(:invalid_ticket) }
115
+ end
116
+
117
+ context 'when the signature is invalid' do
118
+ before :each do
119
+ post_xml :invalid_signature
120
+ end
121
+
122
+ it { should fail_with(:invalid_ticket) }
123
+ end
124
+
125
+ context 'when the cert is wrong' do
126
+ before :each do
127
+ post_xml :invalid_cert
128
+ end
129
+
130
+ it { should fail_with(:invalid_ticket) }
131
+ end
132
+ end
133
+
134
+ describe 'subclass behavior' do
135
+ it 'registers subclasses in OmniAuth.strategies' do
136
+ subclass = Class.new(described_class)
137
+ expect(OmniAuth.strategies).to include(described_class, subclass)
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,27 @@
1
+ if RUBY_VERSION >= '1.9'
2
+ require 'simplecov'
3
+
4
+ if ENV['CI']
5
+ require 'coveralls'
6
+ Coveralls.wear!
7
+ end
8
+
9
+ SimpleCov.start
10
+ end
11
+
12
+ require 'omniauth-signicat'
13
+ require 'rack/test'
14
+ require 'rexml/document'
15
+ require 'rexml/xpath'
16
+ require 'base64'
17
+
18
+ RSpec.configure do |config|
19
+ config.include Rack::Test::Methods
20
+ config.filter_run :focus
21
+ config.run_all_when_everything_filtered = true
22
+ end
23
+
24
+ def load_xml(filename = :example_response)
25
+ filename = File.expand_path(File.join('..', 'support', "#{filename}.xml"), __FILE__)
26
+ Base64.encode64(IO.read(filename))
27
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omniauth-signicat
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Theodor Tonum
8
+ - Raecoo Cao
9
+ - Ryan Wilcox
10
+ - Rajiv Aaron Manglani
11
+ - Steven Anderson
12
+ - Nikos Dimitrakopoulos
13
+ - Rudolf Vriend
14
+ - Bruno Pedro
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+ date: 2016-05-16 00:00:00.000000000 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: omniauth
22
+ requirement: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ type: :runtime
28
+ prerelease: false
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ - !ruby/object:Gem::Dependency
35
+ name: nokogiri
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.5.1
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.5.1
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ - !ruby/object:Gem::Dependency
63
+ name: simplecov
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.11'
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.11'
76
+ - !ruby/object:Gem::Dependency
77
+ name: rack-test
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.6'
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: 0.6.3
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: '0.6'
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 0.6.3
96
+ description: Signicat strategy for OmniAuth.
97
+ email: theodor@nabobil.no
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - CHANGELOG.md
103
+ - LICENSE.md
104
+ - README.md
105
+ - lib/omniauth-signicat.rb
106
+ - lib/omniauth-signicat/version.rb
107
+ - lib/omniauth/strategies/signicat.rb
108
+ - lib/omniauth/strategies/signicat/validation_error.rb
109
+ - spec/omniauth/strategies/signicat_spec.rb
110
+ - spec/spec_helper.rb
111
+ homepage: https://github.com/Nabobil/omniauth-signicat
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.5.1
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Signicat strategy for OmniAuth.
135
+ test_files:
136
+ - spec/omniauth/strategies/signicat_spec.rb
137
+ - spec/spec_helper.rb
138
+ has_rdoc: