omniauth-latvija 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +44 -0
- data/lib/omniauth/strategies/latvija/response.rb +48 -0
- data/lib/omniauth/strategies/latvija/signed_document.rb +95 -0
- data/lib/omniauth/strategies/latvija.rb +74 -0
- data/lib/omniauth-latvija/version.rb +5 -0
- data/lib/omniauth-latvija.rb +2 -0
- metadata +148 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Edgars Beigarts
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# OmniAuth Latvija.lv
|
2
|
+
|
3
|
+
> **Autentifikācijas serviss.** Ar autentifikācijas servisa palīdzību iestādes var ērti savos pakalpojumu portālos vai reģistros autentificēt pakalpojuma lietotāju atbilstoši visiem drošības standartiem. Iestādei vairs nav nepieciešams veidot jaunus autentifikācijas mehānismus un juridiski slēgt vienošanos ar katru no autentifikācijas iespējas nodrošinātājiem. Šobrīd pieejamos autentifikācijas līdzekļus var apskatīties portālā [www.latvija.lv](http://www.latvija.lv/) sadaļā „E-pakalpojumi”.
|
4
|
+
>
|
5
|
+
> -- [VRAA E-pakalpojumi](http://www.vraa.gov.lv/lv/epakalpojumi/viss/)
|
6
|
+
|
7
|
+
Provides the following authentication types:
|
8
|
+
|
9
|
+
* E-paraksts
|
10
|
+
* Swedbank
|
11
|
+
* SEB banka
|
12
|
+
* Online bank
|
13
|
+
* Citadele
|
14
|
+
* Norvik banka
|
15
|
+
* Lattelecom Mobile ID
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'omniauth-latvija', :git => 'http://github.com/ebeigarts/omniauth-latvija.git'
|
21
|
+
```
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
`OmniAuth::Strategies::Latvija` is simply a Rack middleware. Read the OmniAuth 1.x docs for detailed instructions: https://github.com/intridea/omniauth.
|
26
|
+
|
27
|
+
Here's a quick example, adding the middleware to a Rails app in `config/initializers/omniauth.rb`:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
31
|
+
provider :latvija, {
|
32
|
+
:endpoint => "https://epaktv.vraa.gov.lv/IVIS.LVP.STS/Default.aspx",
|
33
|
+
:certificate => File.read("/path/to/cert"),
|
34
|
+
:realm => "urn:federation:example.com"
|
35
|
+
}
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
## References
|
40
|
+
|
41
|
+
* http://docs.oasis-open.org/wsfed/federation/v1.2/os/ws-federation-1.2-spec-os.html
|
42
|
+
* http://msdn.microsoft.com/en-us/library/bb498017.aspx
|
43
|
+
* http://msdn.microsoft.com/en-us/library/bb608217.aspx
|
44
|
+
* https://github.com/onelogin/ruby-saml
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module OmniAuth
|
2
|
+
module Strategies
|
3
|
+
class Latvija
|
4
|
+
class Response
|
5
|
+
ASSERTION = "urn:oasis:names:tc:SAML:1.0:assertion"
|
6
|
+
|
7
|
+
attr_accessor :options, :response, :document
|
8
|
+
|
9
|
+
def initialize(response, options = {})
|
10
|
+
raise ArgumentError.new("Response cannot be nil") if response.nil?
|
11
|
+
self.options = options
|
12
|
+
self.response = response
|
13
|
+
self.document = OmniAuth::Strategies::Latvija::SignedDocument.new(response)
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate!
|
17
|
+
document.validate!(fingerprint)
|
18
|
+
end
|
19
|
+
|
20
|
+
# A hash of alle the attributes with the response. Assuming there is only one value for each key
|
21
|
+
def attributes
|
22
|
+
@attributes ||= begin
|
23
|
+
result = {}
|
24
|
+
|
25
|
+
stmt_element = REXML::XPath.first(document, "//a:Assertion/a:AttributeStatement", { "a" => ASSERTION })
|
26
|
+
return {} if stmt_element.nil?
|
27
|
+
|
28
|
+
stmt_element.elements.each do |attr_element|
|
29
|
+
name = attr_element.attributes["AttributeName"]
|
30
|
+
value = attr_element.elements.first.text
|
31
|
+
|
32
|
+
result[name] = value
|
33
|
+
end
|
34
|
+
|
35
|
+
result
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def fingerprint
|
42
|
+
cert = OpenSSL::X509::Certificate.new(options[:certificate])
|
43
|
+
Digest::SHA1.hexdigest(cert.to_der).upcase.scan(/../).join(":")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# The contents of this file are subject to the terms
|
2
|
+
# of the Common Development and Distribution License
|
3
|
+
# (the License). You may not use this file except in
|
4
|
+
# compliance with the License.
|
5
|
+
#
|
6
|
+
# You can obtain a copy of the License at
|
7
|
+
# https://opensso.dev.java.net/public/CDDLv1.0.html or
|
8
|
+
# opensso/legal/CDDLv1.0.txt
|
9
|
+
# See the License for the specific language governing
|
10
|
+
# permission and limitations under the License.
|
11
|
+
#
|
12
|
+
# When distributing Covered Code, include this CDDL
|
13
|
+
# Header Notice in each file and include the License file
|
14
|
+
# at opensso/legal/CDDLv1.0.txt.
|
15
|
+
# If applicable, add the following below the CDDL Header,
|
16
|
+
# with the fields enclosed by brackets [] replaced by
|
17
|
+
# your own identifying information:
|
18
|
+
# "Portions Copyrighted [year] [name of copyright owner]"
|
19
|
+
#
|
20
|
+
# $Id: xml_sec.rb,v 1.6 2007/10/24 00:28:41 todddd Exp $
|
21
|
+
#
|
22
|
+
# Copyright 2007 Sun Microsystems Inc. All Rights Reserved
|
23
|
+
# Portions Copyrighted 2007 Todd W Saxton.
|
24
|
+
|
25
|
+
module OmniAuth
|
26
|
+
module Strategies
|
27
|
+
class Latvija
|
28
|
+
class SignedDocument < REXML::Document
|
29
|
+
DSIG = "http://www.w3.org/2000/09/xmldsig#"
|
30
|
+
|
31
|
+
attr_accessor :signed_element_id
|
32
|
+
|
33
|
+
def initialize(response)
|
34
|
+
super(response)
|
35
|
+
extract_signed_element_id
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate!(idp_cert_fingerprint)
|
39
|
+
# get cert from response
|
40
|
+
base64_cert = self.elements["//ds:X509Certificate"].text
|
41
|
+
cert_text = Base64.decode64(base64_cert)
|
42
|
+
cert = OpenSSL::X509::Certificate.new(cert_text)
|
43
|
+
|
44
|
+
# check cert matches registered idp cert
|
45
|
+
fingerprint = Digest::SHA1.hexdigest(cert.to_der)
|
46
|
+
|
47
|
+
if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
|
48
|
+
raise ValidationError.new("Fingerprint mismatch")
|
49
|
+
end
|
50
|
+
|
51
|
+
# remove signature node
|
52
|
+
sig_element = REXML::XPath.first(self, "//ds:Signature", { "ds" => DSIG })
|
53
|
+
sig_element.remove
|
54
|
+
|
55
|
+
# check digests
|
56
|
+
REXML::XPath.each(sig_element, "//ds:Reference", {"ds"=>"http://www.w3.org/2000/09/xmldsig#"}) do |ref|
|
57
|
+
uri = ref.attributes.get_attribute("URI").value
|
58
|
+
hashed_element = REXML::XPath.first(self, "//[@AssertionID='#{uri[1,uri.size]}']")
|
59
|
+
canoner = XML::Util::XmlCanonicalizer.new(false, true)
|
60
|
+
canon_hashed_element = canoner.canonicalize(hashed_element)
|
61
|
+
hash = Base64.encode64(Digest::SHA1.digest(canon_hashed_element)).chomp
|
62
|
+
digest_value = REXML::XPath.first(ref, "//ds:DigestValue", { "ds" => DSIG }).text
|
63
|
+
|
64
|
+
if hash != digest_value
|
65
|
+
raise ValidationError.new("Digest mismatch")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# verify signature
|
70
|
+
canoner = XML::Util::XmlCanonicalizer.new(false, true)
|
71
|
+
signed_info_element = REXML::XPath.first(sig_element, "//ds:SignedInfo", { "ds" => DSIG })
|
72
|
+
canon_string = canoner.canonicalize(signed_info_element)
|
73
|
+
|
74
|
+
base64_signature = REXML::XPath.first(sig_element, "//ds:SignatureValue", { "ds" => DSIG }).text
|
75
|
+
signature = Base64.decode64(base64_signature)
|
76
|
+
|
77
|
+
# get certificate object
|
78
|
+
cert_text = Base64.decode64(base64_cert)
|
79
|
+
cert = OpenSSL::X509::Certificate.new(cert_text)
|
80
|
+
|
81
|
+
if !cert.public_key.verify(OpenSSL::Digest::SHA1.new, signature, canon_string)
|
82
|
+
raise ValidationError.new("Key validation error")
|
83
|
+
end
|
84
|
+
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
def extract_signed_element_id
|
89
|
+
reference_element = REXML::XPath.first(self, "//ds:Signature/ds:SignedInfo/ds:Reference", { "ds" => DSIG })
|
90
|
+
self.signed_element_id = reference_element.attribute("URI").value unless reference_element.nil?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "time"
|
2
|
+
require "rexml/document"
|
3
|
+
require "rexml/xpath"
|
4
|
+
require "openssl"
|
5
|
+
require "xmlcanonicalizer"
|
6
|
+
require "digest/sha1"
|
7
|
+
|
8
|
+
require "omniauth/strategies/latvija/response"
|
9
|
+
require "omniauth/strategies/latvija/signed_document"
|
10
|
+
|
11
|
+
module OmniAuth
|
12
|
+
module Strategies
|
13
|
+
#
|
14
|
+
# Authenticate with Latvija.lv.
|
15
|
+
#
|
16
|
+
# @example Basic Rails Usage
|
17
|
+
#
|
18
|
+
# Add this to config/initializers/omniauth.rb
|
19
|
+
#
|
20
|
+
# Rails.application.config.middleware.use OmniAuth::Builder do
|
21
|
+
# provider :latvija, {
|
22
|
+
# :endpoint => "https://epaktv.vraa.gov.lv/IVIS.LVP.STS/Default.aspx",
|
23
|
+
# :certificate => File.read("/path/to/cert"),
|
24
|
+
# :realm => "urn:federation:example.com"
|
25
|
+
# }
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
class Latvija
|
29
|
+
include OmniAuth::Strategy
|
30
|
+
|
31
|
+
class ValidationError < StandardError; end
|
32
|
+
|
33
|
+
def request_phase
|
34
|
+
params = {
|
35
|
+
:wa => 'wsignin1.0',
|
36
|
+
:wct => Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
37
|
+
:wtrealm => @options[:realm],
|
38
|
+
:wreply => callback_url,
|
39
|
+
:wctx => callback_url,
|
40
|
+
:wreq => '<trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512"><trust:Claims xmlns:i="http://schemas.xmlsoap.org/ws/2005/05/identity" Dialect="http://schemas.xmlsoap.org/ws/2005/05/identity"><i:ClaimType Uri="http://docs.oasis-open.org/wsfed/authorization/200706/claims/action" Optional="false" /></trust:Claims><trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType></trust:RequestSecurityToken>'
|
41
|
+
}
|
42
|
+
query_string = params.collect{ |key, value| "#{key}=#{Rack::Utils.escape(value)}" }.join('&')
|
43
|
+
redirect "#{options[:endpoint]}?#{query_string}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def callback_phase
|
47
|
+
if request.params['wresult']
|
48
|
+
@response = OmniAuth::Strategies::Latvija::Response.new(request.params['wresult'], {
|
49
|
+
:certificate => options[:certificate]
|
50
|
+
})
|
51
|
+
@response.validate!
|
52
|
+
super
|
53
|
+
else
|
54
|
+
fail!(:invalid_response)
|
55
|
+
end
|
56
|
+
rescue Exception => e
|
57
|
+
fail!(:invalid_response, e)
|
58
|
+
end
|
59
|
+
|
60
|
+
def auth_hash
|
61
|
+
OmniAuth::Utils.deep_merge(super, {
|
62
|
+
'uid' => "#{@response.attributes['givenname']} #{@response.attributes['surname']}, #{@response.attributes["privatepersonalidentifier"]}",
|
63
|
+
'user_info' => {
|
64
|
+
'name' => "#{@response.attributes['givenname']} #{@response.attributes['surname']}",
|
65
|
+
'first_name' => @response.attributes['givenname'],
|
66
|
+
'last_name' => @response.attributes['surname'],
|
67
|
+
'private_personal_identifier' => @response.attributes['privatepersonalidentifier']
|
68
|
+
},
|
69
|
+
'extra' => @response.attributes
|
70
|
+
})
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omniauth-latvija
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Edgars Beigarts
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: omniauth
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: canonix
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2.10'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2.10'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: simplecov
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rack-test
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: Latvija.lv authentication strategy for OmniAuth
|
111
|
+
email:
|
112
|
+
- edgars.beigarts@makit.lv
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- lib/omniauth/strategies/latvija/response.rb
|
118
|
+
- lib/omniauth/strategies/latvija/signed_document.rb
|
119
|
+
- lib/omniauth/strategies/latvija.rb
|
120
|
+
- lib/omniauth-latvija/version.rb
|
121
|
+
- lib/omniauth-latvija.rb
|
122
|
+
- README.md
|
123
|
+
- LICENSE
|
124
|
+
homepage:
|
125
|
+
licenses: []
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ! '>='
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
requirements: []
|
143
|
+
rubyforge_project:
|
144
|
+
rubygems_version: 1.8.24
|
145
|
+
signing_key:
|
146
|
+
specification_version: 3
|
147
|
+
summary: Latvija.lv authentication strategy for OmniAuth
|
148
|
+
test_files: []
|