omniauth-mpassid 0.1.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 +7 -0
- data/LICENSE +22 -0
- data/README.md +268 -0
- data/Rakefile +17 -0
- data/lib/omniauth/strategies/mpassid.rb +309 -0
- data/lib/omniauth-mpassid/test/certificate_generator.rb +51 -0
- data/lib/omniauth-mpassid/test/utility.rb +46 -0
- data/lib/omniauth-mpassid/test.rb +11 -0
- data/lib/omniauth-mpassid/version.rb +7 -0
- data/lib/omniauth-mpassid.rb +4 -0
- metadata +156 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0ee0bd0d81ad7593a430bdb8ee94ab733d7b396231ac284b7b99b1914d28ff84
|
4
|
+
data.tar.gz: 6e1ef387f6e6f96e8557ced45f60817f8bb6536f7b2e53d5a1da471b82041829
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e4c92ca00791f451b3a86cd8415abd1b45876e3c1515e0d4b6c038a4b293da544ffebef5b43e2c068af8991d3d22384454453b1e3b2f596f2cf129fc41148634
|
7
|
+
data.tar.gz: cf982a1632ee51213463d30ac7d4c1d8f6c06d6e7a499004840b84f85ae731eac46add9d13280953009f1a7294af7659a2b136e8a7bb0975c19d04d6f1f9388b
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2019 Mainio Tech Ltd.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
# OmniAuth MPASSid (SAML 2.0)
|
2
|
+
|
3
|
+
[](https://travis-ci.com/mainio/omniauth-mpassid)
|
4
|
+
[](https://codecov.io/gh/mainio/omniauth-mpassid)
|
5
|
+
|
6
|
+
This is an unofficial OmniAuth strategy for authenticating with the MPASSid
|
7
|
+
identification service used by comprehensive schools and secondary education
|
8
|
+
facilities in Finland. This gem is mostly a configuration wrapper around
|
9
|
+
[`omniauth-saml`](https://github.com/omniauth/omniauth-saml) which uses
|
10
|
+
[`ruby-saml`](https://github.com/onelogin/ruby-saml) for SAML 2.0 based
|
11
|
+
authentication implementation with identity providers, such as MPASSid.
|
12
|
+
|
13
|
+
The gem can be used to hook Ruby/Rails applications to the MPASSid
|
14
|
+
identification service. It does not provide any strong authorization features
|
15
|
+
out of the box, as it does not know anything about the application users, but
|
16
|
+
those can be implemented using this gem and the data provided by the MPASSid
|
17
|
+
identification responses.
|
18
|
+
|
19
|
+
The gem has been developed by [Mainio Tech](https://www.mainiotech.fi/).
|
20
|
+
|
21
|
+
The development has been sponsored by the
|
22
|
+
[City of Helsinki](https://www.hel.fi/).
|
23
|
+
|
24
|
+
The MPASSid service is owned by the Ministry of the Education and Culture in
|
25
|
+
Finland and operated by CSC - Tieteen tietotekniikan keskus Oy. Neither of these
|
26
|
+
parties are related to this gem in any way, nor do they provide technical
|
27
|
+
support for it. Please contact the gem maintainers in case you find any issues
|
28
|
+
with it.
|
29
|
+
|
30
|
+
## Preparation
|
31
|
+
|
32
|
+
In order to start using the MPASSid authentication endpoints, you will need to
|
33
|
+
send a join request to the MPASSid operator for them to configure the identity
|
34
|
+
provider server for your service. Please refer to the MPASSid documentation on
|
35
|
+
how to join the service:
|
36
|
+
|
37
|
+
https://wiki.eduuni.fi/display/CSCMPASSID/Testipalveluun+liittyminen
|
38
|
+
|
39
|
+
Follow the instructions for the SAML2 protocol.
|
40
|
+
|
41
|
+
The details that you need to send to MPASSid are similar to the following
|
42
|
+
information (apply to your service's domain) for non-Rails+Devise applications:
|
43
|
+
|
44
|
+
- SAML2 entity ID: https://www.service.fi/auth/mpassid/metadata
|
45
|
+
- Callback URL (ACS): https://www.service.fi/auth/mpassid/callback
|
46
|
+
|
47
|
+
### Rails and Devise
|
48
|
+
|
49
|
+
When applying this gem to Rails and Devise, the URLs can also include a path
|
50
|
+
prefix to separate the scope of the authentication requests. For example, if
|
51
|
+
you are using a `:user` scope with Devise, the URLs would look like following:
|
52
|
+
|
53
|
+
- SAML2 entity ID: https://www.service.fi/users/auth/mpassid/metadata
|
54
|
+
- Callback URL (ACS): https://www.service.fi/users/auth/mpassid/callback
|
55
|
+
|
56
|
+
## Installation and Configuration
|
57
|
+
|
58
|
+
This gem has been only tested and used with Rails applications using Devise, so
|
59
|
+
this installation guide only covers that part. In case you are interested to
|
60
|
+
learn how you can use this with other frameworks, please refer to the
|
61
|
+
[`omniauth-saml`](https://github.com/omniauth/omniauth-saml) documentation and
|
62
|
+
apply it to your needs (changing the strategy name to `:mpassid` and strategy
|
63
|
+
class to `OmniAuth::Strategies::MPASSid`).
|
64
|
+
|
65
|
+
To install this gem, add the following to your Gemfile:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
gem 'omniauth-mpassid'
|
69
|
+
```
|
70
|
+
|
71
|
+
For configuring the strategy for Devise, add the following in your
|
72
|
+
`config/initializers/devise.rb` file:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
Devise.setup do |config|
|
76
|
+
config.omniauth :mpassid,
|
77
|
+
# The mode needs to be either :production or :test depending on which
|
78
|
+
# MPASSid enviroment you want to hook into. Please note that you will need
|
79
|
+
# to complete the preparation phases even for the test environment.
|
80
|
+
mode: :test, # :production (default, can be omitted) or :test
|
81
|
+
# The service provider entity ID that needs to match the ID you have sent to
|
82
|
+
# the MPASSid operator with your joining request.
|
83
|
+
sp_entity_id: 'https://www.service.fi/auth/mpassid/metadata'
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
## Identification Responses
|
88
|
+
|
89
|
+
The user's data is transmitted from MPASSid in the SAML authentication
|
90
|
+
response. This data will be available in the OmniAuth
|
91
|
+
[extra hash](https://github.com/omniauth/omniauth/wiki/Auth-Hash-Schema#schema-10-and-later).
|
92
|
+
|
93
|
+
In order to access the response data, you can fetch the OmniAuth extra has and
|
94
|
+
the corresponding user data in the OmniAuth callback handler, e.g. in Rails
|
95
|
+
Devise controllers as follows:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
def saml_attributes
|
99
|
+
raw_hash = request.env["omniauth.auth"]
|
100
|
+
extra_hash = raw_hash[:extra]
|
101
|
+
|
102
|
+
extra_hash[:saml_attributes]
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
### Personal Information Transmitted From MPASSid
|
107
|
+
|
108
|
+
The user's personal information transmitted from MPASSid can be found under
|
109
|
+
the `:saml_attributes` key in the OmniAuth extra hash described above.
|
110
|
+
|
111
|
+
This attributes hash will contain the keys described in this following
|
112
|
+
sub-sections. The keys marked as `(undocumented)` are not described in the
|
113
|
+
MPASSid's own documentation but are available at least in some SAML responses.
|
114
|
+
|
115
|
+
See also the MPASSid data models documentation for more information:
|
116
|
+
|
117
|
+
https://wiki.eduuni.fi/display/CSCMPASSID/Data+models
|
118
|
+
|
119
|
+
The attributes can be either single or multi type defining whether they can
|
120
|
+
have a single or multiple values. The single type values are strings and multi
|
121
|
+
type values are arrays of string when the value exists in the SAML response.
|
122
|
+
When the value was not returned from the identity provider's endpoint, the value
|
123
|
+
is `nil` for both types.
|
124
|
+
|
125
|
+
#### `:given_name`
|
126
|
+
|
127
|
+
- SAML URI: urn:oid:2.5.4.42
|
128
|
+
- SAML FriendlyName: givenName
|
129
|
+
- Type: Single (`String`)
|
130
|
+
|
131
|
+
The first/given name of the user.
|
132
|
+
|
133
|
+
#### `:first_names`
|
134
|
+
|
135
|
+
- SAML URI: http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName
|
136
|
+
- SAML FriendlyName: firstName
|
137
|
+
- Type: Single (`String`)
|
138
|
+
|
139
|
+
All the first/given names of the user.
|
140
|
+
|
141
|
+
#### `:last_name`
|
142
|
+
|
143
|
+
- SAML URI: urn:oid:2.5.4.4
|
144
|
+
- SAML FriendlyName: sn
|
145
|
+
- Type: Single (`String`)
|
146
|
+
|
147
|
+
The last/family name of the user.
|
148
|
+
|
149
|
+
#### `:municipality_code`
|
150
|
+
|
151
|
+
- SAML URI: urn:mpass.id:municipalityCode
|
152
|
+
- SAML FriendlyName: municipalityCode
|
153
|
+
- Type: Multi (`Array`)
|
154
|
+
|
155
|
+
The municipality codes of the authenticated user.
|
156
|
+
|
157
|
+
See:
|
158
|
+
|
159
|
+
http://tilastokeskus.fi/meta/luokitukset/kunta/001-2017/index.html
|
160
|
+
|
161
|
+
#### `:municipality_name`
|
162
|
+
|
163
|
+
- SAML URI: one of the following (first found attribute)
|
164
|
+
* urn:mpass.id:municipality
|
165
|
+
* urn:educloudalliance.org:municipality
|
166
|
+
- SAML FriendlyName: one of the following (first found attribute)
|
167
|
+
* N/A
|
168
|
+
* ecaMunicipality
|
169
|
+
- Type: Multi (`Array`)
|
170
|
+
|
171
|
+
The human-readable names of the municipalities of the authenticated user.
|
172
|
+
|
173
|
+
#### `:school_code`
|
174
|
+
|
175
|
+
- SAML URI: urn:mpass.id:municipalityCode
|
176
|
+
- SAML FriendlyName: N/A
|
177
|
+
- Type: Multi (`Array`)
|
178
|
+
|
179
|
+
The school codes of the authenticated user.
|
180
|
+
|
181
|
+
See (JSON format):
|
182
|
+
|
183
|
+
For the list of codes, see:
|
184
|
+
|
185
|
+
- JSON format: https://virkailija.opintopolku.fi/koodisto-service/rest/json/oppilaitosnumero/koodi
|
186
|
+
- XML format: https://virkailija.opintopolku.fi/koodisto-service/rest/oppilaitosnumero/koodi
|
187
|
+
|
188
|
+
An example for a single school code (04647), JSON format:
|
189
|
+
|
190
|
+
https://virkailija.opintopolku.fi/koodisto-service/rest/codeelement/oppilaitosnumero_04647
|
191
|
+
|
192
|
+
#### `:school_name`
|
193
|
+
|
194
|
+
- SAML URI: urn:mpass.id:school
|
195
|
+
- SAML FriendlyName: school
|
196
|
+
- Type: Multi (`Array`)
|
197
|
+
|
198
|
+
The human-readable names of the schools of the authenticated user.
|
199
|
+
|
200
|
+
#### `:class`
|
201
|
+
|
202
|
+
- SAML URI: one of the following (first found attribute)
|
203
|
+
* urn:mpass.id:class
|
204
|
+
* urn:educloudalliance.org:group
|
205
|
+
- SAML FriendlyName: one of the following (first found attribute)
|
206
|
+
* N/A
|
207
|
+
* ecaGroup
|
208
|
+
- Type: Multi (`Array`)
|
209
|
+
|
210
|
+
The class/group-information of the authenticated user.
|
211
|
+
|
212
|
+
For instance: 8A or 3B.
|
213
|
+
|
214
|
+
#### `:class_level`
|
215
|
+
|
216
|
+
- SAML URI: urn:mpass.id:classLevel
|
217
|
+
- SAML FriendlyName: N/A
|
218
|
+
- Type: Multi (`Array`)
|
219
|
+
|
220
|
+
The class/level-information of the authenticated user.
|
221
|
+
|
222
|
+
For instance 8 or 3.
|
223
|
+
|
224
|
+
#### `:role`
|
225
|
+
|
226
|
+
- SAML URI: one of the following (first found attribute)
|
227
|
+
* urn:mpass.id:role
|
228
|
+
* urn:educloudalliance.org:structuredRole
|
229
|
+
- SAML FriendlyName: one of the following (first found attribute)
|
230
|
+
* N/A
|
231
|
+
* ecaStructuredRole
|
232
|
+
- Type: Multi (`Array`)
|
233
|
+
|
234
|
+
The roles of the user in four parts, divided with a semicolon (;) character.
|
235
|
+
First municipality, followed by school code, group and role in the group.
|
236
|
+
|
237
|
+
For instance Helsinki;32132;9A;Oppilas.
|
238
|
+
|
239
|
+
#### `:role_name` (undocumented)
|
240
|
+
|
241
|
+
- SAML URI: urn:educloudalliance.org:role
|
242
|
+
- SAML FriendlyName: ecaRole
|
243
|
+
- Type: Multi (`Array`)
|
244
|
+
|
245
|
+
NOTE: This attribute is undocumented by MPASSid.
|
246
|
+
|
247
|
+
The human readable names of the role (in Finnish).
|
248
|
+
|
249
|
+
For instance Oppilas.
|
250
|
+
|
251
|
+
#### `:funet_person_learner_id` (undocumented)
|
252
|
+
|
253
|
+
- SAML URI: urn:oid:1.3.6.1.4.1.16161.1.1.27
|
254
|
+
- SAML FriendlyName: N/A
|
255
|
+
- Type: Single (`String`)
|
256
|
+
|
257
|
+
NOTE: This attribute is undocumented by MPASSid.
|
258
|
+
|
259
|
+
11-digit identifier, which may be used to identify a person while storing,
|
260
|
+
managing or transferring personal data.
|
261
|
+
|
262
|
+
See:
|
263
|
+
|
264
|
+
https://wiki.eduuni.fi/display/CSCHAKA/funetEduPersonSchema2dot2#funetEduPersonSchema2dot2-funetEduPersonLearnerId
|
265
|
+
|
266
|
+
## License
|
267
|
+
|
268
|
+
MIT, see [LICENSE](LICENSE).
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
# Run all tests, with coverage report
|
6
|
+
RSpec::Core::RakeTask.new(:coverage) do |t|
|
7
|
+
ENV['CODECOV'] = '1'
|
8
|
+
t.verbose = false
|
9
|
+
end
|
10
|
+
|
11
|
+
# Run all tests, include all
|
12
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
13
|
+
t.verbose = false
|
14
|
+
end
|
15
|
+
|
16
|
+
# Default
|
17
|
+
task default: :coverage
|
@@ -0,0 +1,309 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'omniauth-saml'
|
4
|
+
|
5
|
+
module OmniAuth
|
6
|
+
module Strategies
|
7
|
+
class MPASSid < SAML
|
8
|
+
# Mode:
|
9
|
+
# :production - MPASSid production environment
|
10
|
+
# :test - MPASSid test environment
|
11
|
+
option :mode, :production
|
12
|
+
|
13
|
+
# The request attributes for MPASSid
|
14
|
+
option :request_attributes, [
|
15
|
+
# The unique identifier of the authenticated user. Currently recommended
|
16
|
+
# identifier for identifying the user. NOTE: will change if the user
|
17
|
+
# moves to another user registry.
|
18
|
+
# (single value)
|
19
|
+
{
|
20
|
+
name: 'urn:mpass.id:uid',
|
21
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'
|
22
|
+
},
|
23
|
+
# Funet EDU person learner ID
|
24
|
+
# (single value)
|
25
|
+
{
|
26
|
+
name: 'urn:oid:1.3.6.1.4.1.16161.1.1.27',
|
27
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'
|
28
|
+
},
|
29
|
+
# The first/given name of the user.
|
30
|
+
# (single value)
|
31
|
+
{
|
32
|
+
name: 'urn:oid:2.5.4.42',
|
33
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
34
|
+
friendly_name: 'givenName'
|
35
|
+
},
|
36
|
+
# All the first/given names of the user.
|
37
|
+
# (single value)
|
38
|
+
{
|
39
|
+
name: 'http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName',
|
40
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
41
|
+
friendly_name: 'firstName'
|
42
|
+
},
|
43
|
+
# The last/family name of the user.
|
44
|
+
# (single value)
|
45
|
+
{
|
46
|
+
name: 'urn:oid:2.5.4.4',
|
47
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
48
|
+
friendly_name: 'sn'
|
49
|
+
},
|
50
|
+
# The municipality code of the authenticated user. See
|
51
|
+
# http://tilastokeskus.fi/meta/luokitukset/kunta/001-2017/index.html
|
52
|
+
# for mappings in Finland.
|
53
|
+
# (multi value)
|
54
|
+
{
|
55
|
+
name: 'urn:mpass.id:municipalityCode',
|
56
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
57
|
+
friendly_name: 'municipalityCode'
|
58
|
+
},
|
59
|
+
# The human-readable name of the municipality of the authenticated user.
|
60
|
+
# (multi value)
|
61
|
+
{
|
62
|
+
name: 'urn:mpass.id:municipality',
|
63
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'
|
64
|
+
},
|
65
|
+
{
|
66
|
+
name: 'urn:educloudalliance.org:municipality',
|
67
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
68
|
+
friendly_name: 'ecaMunicipality'
|
69
|
+
},
|
70
|
+
# The school code of the authenticated user. See
|
71
|
+
# https://virkailija.opintopolku.fi/koodisto-service/rest/json/oppilaitosnumero/koodi
|
72
|
+
# (JSON format)
|
73
|
+
# https://virkailija.opintopolku.fi/koodisto-service/rest/oppilaitosnumero/koodi
|
74
|
+
# (XML format)
|
75
|
+
# for the mappings in Finland. For example,
|
76
|
+
# https://virkailija.opintopolku.fi/koodisto-service/rest/codeelement/oppilaitosnumero_04647
|
77
|
+
# for school code 04647.
|
78
|
+
# (multi value)
|
79
|
+
{
|
80
|
+
name: 'urn:mpass.id:schoolCode',
|
81
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'
|
82
|
+
},
|
83
|
+
# The human-readable name of the school of the authenticated user.
|
84
|
+
# (multi value)
|
85
|
+
{
|
86
|
+
name: 'urn:mpass.id:school',
|
87
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
88
|
+
friendly_name: 'school'
|
89
|
+
},
|
90
|
+
# The class/group-information of the authenticated user.
|
91
|
+
# For instance: 8A or 3B.
|
92
|
+
# (multi value)
|
93
|
+
{
|
94
|
+
name: 'urn:mpass.id:class',
|
95
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'
|
96
|
+
},
|
97
|
+
{
|
98
|
+
name: 'urn:educloudalliance.org:group',
|
99
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
100
|
+
friendly_name: 'ecaGroup'
|
101
|
+
},
|
102
|
+
# The class/level-information of the authenticated user.
|
103
|
+
# For instance 8 or 3.
|
104
|
+
# (multi value)
|
105
|
+
{
|
106
|
+
name: 'urn:mpass.id:classLevel',
|
107
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'
|
108
|
+
},
|
109
|
+
# The role name of the user.
|
110
|
+
# For instance Oppilas.
|
111
|
+
# (multi value)
|
112
|
+
{
|
113
|
+
name: 'urn:educloudalliance.org:role',
|
114
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
115
|
+
friendly_name: 'ecaRole'
|
116
|
+
},
|
117
|
+
# The role of the user in four parts, divided with a semicolon (;)
|
118
|
+
# character. First municipality, followed by school code, group and role
|
119
|
+
# in the group.
|
120
|
+
# For instance Helsinki;32132;9A;Oppilas.
|
121
|
+
# (multi value)
|
122
|
+
{
|
123
|
+
name: 'urn:mpass.id:role',
|
124
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'
|
125
|
+
},
|
126
|
+
{
|
127
|
+
name: 'urn:educloudalliance.org:structuredRole',
|
128
|
+
name_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
129
|
+
friendly_name: 'ecaStructuredRole'
|
130
|
+
}
|
131
|
+
]
|
132
|
+
|
133
|
+
# Maps the SAML attributes to OmniAuth info schema:
|
134
|
+
# https://github.com/omniauth/omniauth/wiki/Auth-Hash-Schema#schema-10-and-later
|
135
|
+
option(
|
136
|
+
:attribute_statements,
|
137
|
+
# Given name or all first names (in case given name is not found)
|
138
|
+
first_name: ['urn:oid:2.5.4.42', 'http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName'],
|
139
|
+
last_name: ['urn:oid:2.5.4.4'],
|
140
|
+
# The municipality of the person (literal format in Finnish)
|
141
|
+
location: ['urn:mpass.id:municipality', 'urn:educloudalliance.org:municipality']
|
142
|
+
)
|
143
|
+
|
144
|
+
info do
|
145
|
+
# Generate the full name to the info hash
|
146
|
+
first_name = find_attribute_by(
|
147
|
+
[
|
148
|
+
'urn:oid:2.5.4.42',
|
149
|
+
'http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName'
|
150
|
+
]
|
151
|
+
)
|
152
|
+
last_name = find_attribute_by(['urn:oid:2.5.4.4'])
|
153
|
+
display_name = "#{first_name} #{last_name}".strip
|
154
|
+
display_name = nil if display_name.length.zero?
|
155
|
+
|
156
|
+
found_attributes = [[:name, display_name]]
|
157
|
+
|
158
|
+
# Default functionality from omniauth-saml
|
159
|
+
found_attributes += options.attribute_statements.map do |key, values|
|
160
|
+
attribute = find_attribute_by(values)
|
161
|
+
[key, attribute]
|
162
|
+
end
|
163
|
+
|
164
|
+
Hash[found_attributes]
|
165
|
+
end
|
166
|
+
|
167
|
+
option(
|
168
|
+
:security_settings,
|
169
|
+
digest_method: XMLSecurity::Document::SHA256,
|
170
|
+
signature_method: XMLSecurity::Document::RSA_SHA256
|
171
|
+
)
|
172
|
+
|
173
|
+
# The attribute key maps to the SAML URIs so that we have more descriptive
|
174
|
+
# attribute keys available for use. These will be mapped to the OmniAuth
|
175
|
+
# `extra` information hash under the `:saml_attributes` key.
|
176
|
+
option(
|
177
|
+
:saml_attributes_map,
|
178
|
+
given_name: ['urn:oid:2.5.4.42'],
|
179
|
+
first_names: ['http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName'],
|
180
|
+
last_name: ['urn:oid:2.5.4.4'],
|
181
|
+
municipality_code: {
|
182
|
+
name: ['urn:mpass.id:municipalityCode'],
|
183
|
+
type: :multi
|
184
|
+
},
|
185
|
+
municipality_name: {
|
186
|
+
name: ['urn:mpass.id:municipality', 'urn:educloudalliance.org:municipality'],
|
187
|
+
type: :multi
|
188
|
+
},
|
189
|
+
school_code: {
|
190
|
+
name: ['urn:mpass.id:schoolCode'],
|
191
|
+
type: :multi
|
192
|
+
},
|
193
|
+
school_name: {
|
194
|
+
name: ['urn:mpass.id:school'],
|
195
|
+
type: :multi
|
196
|
+
},
|
197
|
+
class: {
|
198
|
+
name: ['urn:mpass.id:class', 'urn:educloudalliance.org:group'],
|
199
|
+
type: :multi
|
200
|
+
},
|
201
|
+
class_level: {
|
202
|
+
name: ['urn:mpass.id:classLevel'],
|
203
|
+
type: :multi
|
204
|
+
},
|
205
|
+
role: {
|
206
|
+
name: ['urn:mpass.id:role', 'urn:educloudalliance.org:structuredRole'],
|
207
|
+
type: :multi
|
208
|
+
},
|
209
|
+
role_name: {
|
210
|
+
name: ['urn:educloudalliance.org:role'],
|
211
|
+
type: :multi
|
212
|
+
},
|
213
|
+
# Extra (undocumented)
|
214
|
+
funet_person_learner_id: ['urn:oid:1.3.6.1.4.1.16161.1.1.27']
|
215
|
+
)
|
216
|
+
|
217
|
+
# Defines the SAML attribute from which to determine the OmniAuth `uid`.
|
218
|
+
# NOTE:
|
219
|
+
# In case the user moves to another user registry, this will change.
|
220
|
+
# However, there is no other unique identifier passed along the SAML
|
221
|
+
# attributes that we could rely on, so this is the best bet.
|
222
|
+
option :uid_attribute, 'urn:mpass.id:uid'
|
223
|
+
|
224
|
+
# Add the SAML attributes to the extra hash for easier access.
|
225
|
+
extra { {saml_attributes: saml_attributes} }
|
226
|
+
|
227
|
+
def initialize(app, *args, &block)
|
228
|
+
super
|
229
|
+
|
230
|
+
# Add the MPASSid options to the local options, most of which are
|
231
|
+
# fetched from the metadata. The options array is the one that gets
|
232
|
+
# priority in case it overrides some of the metadata or locally defined
|
233
|
+
# option values.
|
234
|
+
@options = OmniAuth::Strategy::Options.new(
|
235
|
+
mpassid_options.merge(options)
|
236
|
+
)
|
237
|
+
end
|
238
|
+
|
239
|
+
# This method can be used externally to fetch information about the
|
240
|
+
# response, e.g. in case of failures.
|
241
|
+
def response_object
|
242
|
+
return nil unless request.params['SAMLResponse']
|
243
|
+
|
244
|
+
with_settings do |settings|
|
245
|
+
response = OneLogin::RubySaml::Response.new(
|
246
|
+
request.params['SAMLResponse'],
|
247
|
+
options_for_response_object.merge(settings: settings)
|
248
|
+
)
|
249
|
+
response.attributes['fingerprint'] = settings.idp_cert_fingerprint
|
250
|
+
response
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
private
|
255
|
+
|
256
|
+
def idp_metadata_url
|
257
|
+
case options.mode
|
258
|
+
when :test
|
259
|
+
'https://mpass-proxy-test.csc.fi/idp/shibboleth'
|
260
|
+
else
|
261
|
+
'https://mpass-proxy.csc.fi/idp/shibboleth'
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def mpassid_options
|
266
|
+
idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
|
267
|
+
|
268
|
+
# Returns OneLogin::RubySaml::Settings prepopulated with idp metadata
|
269
|
+
# We are using the redirect binding for the SSO and SLO URLs as these
|
270
|
+
# are the ones expected by omniauth-saml. Otherwise the default would be
|
271
|
+
# the first one defined in the IdP metadata, which would be the
|
272
|
+
# HTTP-POST binding.
|
273
|
+
settings = idp_metadata_parser.parse_remote_to_hash(
|
274
|
+
idp_metadata_url,
|
275
|
+
true,
|
276
|
+
sso_binding: ['urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect']
|
277
|
+
)
|
278
|
+
|
279
|
+
# Define the security settings as there are some defaults that need to be
|
280
|
+
# modified
|
281
|
+
security_defaults = OneLogin::RubySaml::Settings::DEFAULTS[:security]
|
282
|
+
settings[:security] = security_defaults.merge(options.security_settings)
|
283
|
+
|
284
|
+
settings
|
285
|
+
end
|
286
|
+
|
287
|
+
def saml_attributes
|
288
|
+
{}.tap do |attrs|
|
289
|
+
options.saml_attributes_map.each do |target, definition|
|
290
|
+
unless definition.is_a?(Hash)
|
291
|
+
definition = {
|
292
|
+
name: definition,
|
293
|
+
type: :single
|
294
|
+
}
|
295
|
+
end
|
296
|
+
|
297
|
+
value = definition[:name].map do |key|
|
298
|
+
@attributes.public_send(definition[:type], key)
|
299
|
+
end.reject(&:nil?).first
|
300
|
+
|
301
|
+
attrs[target] = value
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
OmniAuth.config.add_camelization 'mpassid', 'MPASSid'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAuth
|
4
|
+
module MPASSid
|
5
|
+
module Test
|
6
|
+
class CertificateGenerator
|
7
|
+
def private_key
|
8
|
+
@private_key ||= OpenSSL::PKey::RSA.new(2048)
|
9
|
+
end
|
10
|
+
|
11
|
+
def certificate
|
12
|
+
@certificate ||= begin
|
13
|
+
public_key = private_key.public_key
|
14
|
+
|
15
|
+
subject = '/C=FI/O=Test/OU=Test/CN=Test'
|
16
|
+
|
17
|
+
cert = OpenSSL::X509::Certificate.new
|
18
|
+
cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
|
19
|
+
cert.not_before = Time.now
|
20
|
+
cert.not_after = Time.now + 365 * 24 * 60 * 60
|
21
|
+
cert.public_key = public_key
|
22
|
+
cert.serial = 0x0
|
23
|
+
cert.version = 2
|
24
|
+
|
25
|
+
inject_certificate_extensions(cert)
|
26
|
+
|
27
|
+
cert.sign(private_key, OpenSSL::Digest::SHA1.new)
|
28
|
+
|
29
|
+
cert
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def inject_certificate_extensions(cert)
|
36
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
37
|
+
ef.subject_certificate = cert
|
38
|
+
ef.issuer_certificate = cert
|
39
|
+
cert.extensions = [
|
40
|
+
ef.create_extension('basicConstraints', 'CA:TRUE', true),
|
41
|
+
ef.create_extension('subjectKeyIdentifier', 'hash')
|
42
|
+
]
|
43
|
+
cert.add_extension ef.create_extension(
|
44
|
+
'authorityKeyIdentifier',
|
45
|
+
'keyid:always,issuer:always'
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAuth
|
4
|
+
module MPASSid
|
5
|
+
module Test
|
6
|
+
class Utility
|
7
|
+
def self.inflate_xml(encoded_deflated_xml)
|
8
|
+
deflated_xml = Base64.decode64(encoded_deflated_xml)
|
9
|
+
Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(deflated_xml)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.signed_xml(raw_xml_file, opts)
|
13
|
+
raw_xml = IO.read(raw_xml_file)
|
14
|
+
signed_xml_from_string(raw_xml, opts)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.signed_xml_from_string(raw_xml, opts)
|
18
|
+
sign_xml_element(
|
19
|
+
raw_xml,
|
20
|
+
opts[:sign_certificate],
|
21
|
+
opts[:sign_private_key]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.sign_xml_element(element, sign_certificate, sign_key)
|
26
|
+
doc = XMLSecurity::Document.new(element)
|
27
|
+
doc.sign_document(
|
28
|
+
sign_key,
|
29
|
+
sign_certificate,
|
30
|
+
XMLSecurity::Document::RSA_SHA256,
|
31
|
+
XMLSecurity::Document::SHA256
|
32
|
+
)
|
33
|
+
# Move the signature to the correct position, otherwise schema
|
34
|
+
# validation does not work because the internal logic of ruby-saml
|
35
|
+
# cannot handle custom element names (saml2:Issuer instead of
|
36
|
+
# saml:Issuer).
|
37
|
+
signature = doc.delete_element('//ds:Signature')
|
38
|
+
issuer = doc.elements['//saml2:Issuer']
|
39
|
+
doc.root.insert_after(issuer, signature)
|
40
|
+
|
41
|
+
doc.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omniauth-mpassid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Antti Hukkanen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-08-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: omniauth-saml
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.10.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.10.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack-test
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.1.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.1.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.6'
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 3.6.2
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - "~>"
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '3.6'
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 3.6.2
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: xmlenc
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 0.7.1
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.7.1
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: simplecov
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.16.0
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 0.16.0
|
117
|
+
description: MPASSid identification service integration for OmniAuth.
|
118
|
+
email:
|
119
|
+
- antti.hukkanen@mainiotech.fi
|
120
|
+
executables: []
|
121
|
+
extensions: []
|
122
|
+
extra_rdoc_files: []
|
123
|
+
files:
|
124
|
+
- LICENSE
|
125
|
+
- README.md
|
126
|
+
- Rakefile
|
127
|
+
- lib/omniauth-mpassid.rb
|
128
|
+
- lib/omniauth-mpassid/test.rb
|
129
|
+
- lib/omniauth-mpassid/test/certificate_generator.rb
|
130
|
+
- lib/omniauth-mpassid/test/utility.rb
|
131
|
+
- lib/omniauth-mpassid/version.rb
|
132
|
+
- lib/omniauth/strategies/mpassid.rb
|
133
|
+
homepage: https://github.com/mainio/omniauth-mpassid
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubygems_version: 3.0.3
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: Provides an MPASSid strategy for OmniAuth.
|
156
|
+
test_files: []
|