omniauth-signicat 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: