omniauth-latvija 1.1.1 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0239b9b5db1634778428119aa3ccd7babdf2feb5
4
- data.tar.gz: 87a622416084055bb8433baafbea7a4416536cb1
3
+ metadata.gz: 875159da4f23d72890c3da6c24f1b174d197f6ec
4
+ data.tar.gz: af5a474b33c9165faf67a14a61b8785e0567a456
5
5
  SHA512:
6
- metadata.gz: 43ea0a0b2aca412cd61c73ec9e0e507dcb64f1db84c8057955cf22a347f5914c5e35c7fe7e586036c8b63d8b5cb8c3e055f0d814c418287f1c8cb373d3f37c7e
7
- data.tar.gz: a87c8ffdd361578b2fc2c7d945ac4e4712a9f1514f83a942c31452dd2c54228750fdb551410f16a670e1a3d38d15af61cfed60503ea084dfbac9b9fbd7d3cfca
6
+ metadata.gz: 36fc98917bfe2547d020287fc90f6c4dcc986722c903be7acf49a3ffe56d7899d097661a0620352bb95646cfbc6db250cf911b89b2bbf603db1e3cc5125defed
7
+ data.tar.gz: 1f5947b59168bf23f22ab34c7b4b5ec83c2e01f4402a7035400bd885d00a3751d6eebffa741902f2c149a5d730b1f9ffb038f84015f40b6c514fe624290fe862
data/README.md CHANGED
@@ -12,12 +12,14 @@ Provides the following authentication types:
12
12
  * Online bank
13
13
  * Citadele
14
14
  * Norvik banka
15
+ * PrivatBank
16
+ * eID
15
17
  * Lattelecom Mobile ID
16
18
 
17
19
  ## Installation
18
20
 
19
21
  ```ruby
20
- gem 'omniauth-latvija', :git => 'http://github.com/ebeigarts/omniauth-latvija.git'
22
+ gem 'omniauth-latvija', '~> 2.0'
21
23
  ```
22
24
 
23
25
  ## Usage
@@ -29,9 +31,10 @@ Here's a quick example, adding the middleware to a Rails app in `config/initiali
29
31
  ```ruby
30
32
  Rails.application.config.middleware.use OmniAuth::Builder do
31
33
  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"
34
+ endpoint: "https://epaktv.vraa.gov.lv/IVIS.LVP.STS/Default.aspx",
35
+ certificate: File.read("/path/to/cert.pem"),
36
+ private_key: File.read("/path/to/private_key.pem"), # mandatory, if the response is encrypted
37
+ realm: "urn:federation:example.com"
35
38
  }
36
39
  end
37
40
  ```
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module Latvija
3
- VERSION = '1.1.1'
3
+ VERSION = '2.0.0'
4
4
  end
5
5
  end
@@ -1,76 +1,81 @@
1
- require "time"
2
- require "rexml/document"
3
- require "rexml/xpath"
4
- require "openssl"
5
- require "xmlcanonicalizer"
6
- require "digest/sha1"
1
+ require 'time'
2
+ require 'openssl'
3
+ require 'digest/sha1'
4
+ require 'xmlenc'
5
+ require 'nokogiri'
6
+ require 'omniauth/strategies/latvija/response'
7
+ require 'omniauth/strategies/latvija/decryptor'
8
+ require 'omniauth/strategies/latvija/signed_document'
7
9
 
8
- require "omniauth/strategies/latvija/response"
9
- require "omniauth/strategies/latvija/signed_document"
10
+ module OmniAuth::Strategies
11
+ #
12
+ # Authenticate with Latvija.lv.
13
+ #
14
+ # @example Basic Rails Usage
15
+ #
16
+ # Add this to config/initializers/omniauth.rb
17
+ #
18
+ # Rails.application.config.middleware.use OmniAuth::Builder do
19
+ # provider :latvija, {
20
+ # endpoint: "https://epaktv.vraa.gov.lv/IVIS.LVP.STS/Default.aspx",
21
+ # certificate: File.read("/path/to/cert"),
22
+ # private: File.read("/path/to/private_key"),
23
+ # realm: "urn:federation:example.com"
24
+ # }
25
+ # end
26
+ #
27
+ class Latvija
28
+ include OmniAuth::Strategy
29
+ class ValidationError < StandardError; end
10
30
 
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
31
+ option :realm, nil
32
+ option :wfresh, false
33
+ option :endpoint, nil
34
+ option :certificate, nil
35
+ option :private_key, nil
30
36
 
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
- params[:wfresh] = @options[:wfresh] if @options[:wfresh]
43
- query_string = params.collect{ |key, value| "#{key}=#{Rack::Utils.escape(value)}" }.join('&')
44
- redirect "#{options[:endpoint]}?#{query_string}"
45
- end
37
+ def request_phase
38
+ params = {
39
+ wa: 'wsignin1.0',
40
+ wct: Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ'),
41
+ wtrealm: options[:realm],
42
+ wreply: callback_url,
43
+ wctx: callback_url,
44
+ 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>'
45
+ }
46
+ params[:wfresh] = options[:wfresh] if options[:wfresh]
47
+ query_string = params.collect { |key, value| "#{key}=#{Rack::Utils.escape(value)}" }.join('&')
48
+ redirect "#{options[:endpoint]}?#{query_string}"
49
+ end
46
50
 
47
- def callback_phase
48
- if request.params['wresult']
49
- @response = OmniAuth::Strategies::Latvija::Response.new(request.params['wresult'], {
50
- :certificate => options[:certificate]
51
- })
52
- @response.validate!
53
- super
54
- else
55
- fail!(:invalid_response)
56
- end
57
- rescue Exception => e
58
- fail!(:invalid_response, e)
51
+ def callback_phase
52
+ if request.params['wresult']
53
+ @response = OmniAuth::Strategies::Latvija::Response.new(
54
+ request.params['wresult'],
55
+ certificate: options[:certificate],
56
+ private_key: options[:private_key]
57
+ )
58
+ @response.validate!
59
+ super
60
+ else
61
+ fail!(:invalid_response)
59
62
  end
63
+ rescue Exception => e
64
+ fail!(:invalid_response, e)
65
+ end
60
66
 
61
- def auth_hash
62
- OmniAuth::Utils.deep_merge(super, {
63
- 'uid' => "#{@response.attributes['givenname']} #{@response.attributes['surname']}, #{@response.attributes["privatepersonalidentifier"]}",
64
- 'user_info' => {
65
- 'name' => "#{@response.attributes['givenname']} #{@response.attributes['surname']}",
66
- 'first_name' => @response.attributes['givenname'],
67
- 'last_name' => @response.attributes['surname'],
68
- 'private_personal_identifier' => @response.attributes['privatepersonalidentifier']
69
- },
70
- 'authentication_method' => @response.authentication_method,
71
- 'extra' => @response.attributes
72
- })
73
- end
67
+ def auth_hash
68
+ OmniAuth::Utils.deep_merge(super,
69
+ uid: "#{@response.attributes['givenname']} #{@response.attributes['surname']}, #{@response.attributes["privatepersonalidentifier"]}",
70
+ user_info: {
71
+ name: "#{@response.attributes['givenname']} #{@response.attributes['surname']}",
72
+ first_name: @response.attributes['givenname'],
73
+ last_name: @response.attributes['surname'],
74
+ private_personal_identifier: @response.attributes['privatepersonalidentifier']
75
+ },
76
+ authentication_method: @response.authentication_method,
77
+ extra: @response.attributes
78
+ )
74
79
  end
75
80
  end
76
81
  end
@@ -0,0 +1,16 @@
1
+ module OmniAuth::Strategies
2
+ class Latvija
3
+ class Decryptor
4
+ def initialize(response, key)
5
+ @response = response
6
+ @key = key
7
+ end
8
+
9
+ def decrypt
10
+ private_key = OpenSSL::PKey::RSA.new(@key)
11
+ encrypted_document = Xmlenc::EncryptedDocument.new(@response)
12
+ encrypted_document.decrypt(private_key)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,53 +1,53 @@
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
1
+ module OmniAuth::Strategies
2
+ class Latvija
3
+ class Response
4
+ ASSERTION = 'urn:oasis:names:tc:SAML:1.0:assertion'.freeze
5
+
6
+ attr_accessor :options, :response
7
+
8
+ def initialize(response, **options)
9
+ raise ArgumentError, 'Response cannot be nil' if response.nil?
10
+ @options = options
11
+ @response = response
12
+ @document = OmniAuth::Strategies::Latvija::SignedDocument.new(response, private_key: options[:private_key])
13
+ end
15
14
 
16
- def validate!
17
- document.validate!(fingerprint)
18
- end
15
+ def validate!
16
+ @document.validate!(fingerprint)
17
+ end
19
18
 
20
- def authentication_method
21
- @authentication_method ||= begin
22
- REXML::XPath.first(document, "//saml:AuthenticationStatement").attributes['AuthenticationMethod']
23
- end
24
- end
19
+ def xml
20
+ @document.nokogiri_xml
21
+ end
25
22
 
26
- # A hash of alle the attributes with the response. Assuming there is only one value for each key
27
- def attributes
28
- @attributes ||= begin
29
- result = {}
23
+ def authentication_method
24
+ @authentication_method ||= begin
25
+ xml.xpath('//saml:AuthenticationStatement', saml: ASSERTION).attribute('AuthenticationMethod')
26
+ end
27
+ end
30
28
 
31
- stmt_element = REXML::XPath.first(document, "//a:Assertion/a:AttributeStatement", { "a" => ASSERTION })
32
- return {} if stmt_element.nil?
29
+ # A hash of all the attributes with the response.
30
+ # Assuming there is only one value for each key
31
+ def attributes
32
+ @attributes ||= begin
33
33
 
34
- stmt_element.elements.each do |attr_element|
35
- name = attr_element.attributes["AttributeName"]
36
- value = attr_element.elements.first.text
34
+ stmt_elements = xml.xpath('//a:Attribute', a: ASSERTION)
35
+ return {} if stmt_elements.nil?
37
36
 
38
- result[name] = value
39
- end
37
+ stmt_elements.each_with_object({}) do |element, result|
38
+ name = element.attribute('AttributeName').value
39
+ value = element.text
40
40
 
41
- result
41
+ result[name] = value
42
42
  end
43
43
  end
44
+ end
44
45
 
45
- private
46
+ private
46
47
 
47
- def fingerprint
48
- cert = OpenSSL::X509::Certificate.new(options[:certificate])
49
- Digest::SHA1.hexdigest(cert.to_der).upcase.scan(/../).join(":")
50
- end
48
+ def fingerprint
49
+ cert = OpenSSL::X509::Certificate.new(options[:certificate])
50
+ Digest::SHA1.hexdigest(cert.to_der).upcase.scan(/../).join(':')
51
51
  end
52
52
  end
53
53
  end
@@ -15,79 +15,87 @@
15
15
  # If applicable, add the following below the CDDL Header,
16
16
  # with the fields enclosed by brackets [] replaced by
17
17
  # your own identifying information:
18
- # "Portions Copyrighted [year] [name of copyright owner]"
18
+ # 'Portions Copyrighted [year] [name of copyright owner]'
19
19
  #
20
20
  # $Id: xml_sec.rb,v 1.6 2007/10/24 00:28:41 todddd Exp $
21
21
  #
22
22
  # Copyright 2007 Sun Microsystems Inc. All Rights Reserved
23
23
  # Portions Copyrighted 2007 Todd W Saxton.
24
24
 
25
- module OmniAuth
26
- module Strategies
27
- class Latvija
28
- class SignedDocument < REXML::Document
29
- DSIG = "http://www.w3.org/2000/09/xmldsig#"
25
+ module OmniAuth::Strategies
26
+ class Latvija
27
+ class SignedDocument
28
+ DSIG = 'http://www.w3.org/2000/09/xmldsig#'.freeze
29
+ XENC = 'http://www.w3.org/2001/04/xmlenc#'.freeze
30
+ CANON_MODE = Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
30
31
 
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)
32
+ def initialize(response, **opts)
33
+ @response = Nokogiri::XML.parse(response, &:noblanks)
34
+ return unless encrypted?
35
+ decryptor = OmniAuth::Strategies::Latvija::Decryptor.new(response, opts[:private_key])
36
+ decrypted_response = decryptor.decrypt
37
+ @response = Nokogiri::XML.parse(decrypted_response, &:noblanks)
38
+ end
43
39
 
44
- # check cert matches registered idp cert
45
- fingerprint = Digest::SHA1.hexdigest(cert.to_der)
40
+ def validate!(idp_cert_fingerprint)
41
+ validate_fingerprint!(idp_cert_fingerprint)
42
+ sig_element = @response.xpath('//xmlns:Signature', xmlns: DSIG)
46
43
 
47
- if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
48
- raise ValidationError.new("Fingerprint mismatch")
49
- end
44
+ validate_digest!(sig_element)
45
+ validate_signature!(sig_element)
46
+ true
47
+ end
50
48
 
51
- # remove signature node
52
- sig_element = REXML::XPath.first(self, "//ds:Signature", { "ds" => DSIG })
53
- sig_element.remove
49
+ def nokogiri_xml
50
+ @response
51
+ end
54
52
 
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
53
+ private
63
54
 
64
- if hash != digest_value
65
- raise ValidationError.new("Digest mismatch")
66
- end
67
- end
55
+ def encrypted?
56
+ @response.xpath('//xenc:EncryptedData', 'xmlns:xenc' => XENC).any?
57
+ end
68
58
 
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)
59
+ def certificate
60
+ @certificate ||= begin
61
+ base64_cert = @response.xpath('//xmlns:X509Certificate', xmlns: DSIG).text
62
+ cert_text = Base64.decode64(base64_cert)
63
+ OpenSSL::X509::Certificate.new(cert_text)
64
+ end
65
+ end
73
66
 
74
- base64_signature = REXML::XPath.first(sig_element, "//ds:SignatureValue", { "ds" => DSIG }).text
75
- signature = Base64.decode64(base64_signature)
67
+ def validate_fingerprint!(idp_cert_fingerprint)
68
+ fingerprint = Digest::SHA1.hexdigest(certificate.to_der)
69
+ if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/, '').downcase
70
+ raise ValidationError, 'Fingerprint mismatch'
71
+ end
72
+ end
76
73
 
77
- # get certificate object
78
- cert_text = Base64.decode64(base64_cert)
79
- cert = OpenSSL::X509::Certificate.new(cert_text)
74
+ def validate_digest!(sig_element)
75
+ response_without_signature = @response.dup
76
+ response_without_signature.xpath('//xmlns:Signature', xmlns: DSIG).remove
80
77
 
81
- if !cert.public_key.verify(OpenSSL::Digest::SHA1.new, signature, canon_string)
82
- raise ValidationError.new("Key validation error")
83
- end
78
+ sig_element.xpath('.//xmlns:Reference', xmlns: DSIG).each do |ref|
79
+ uri = ref.attribute('URI').value
80
+ hashed_element = response_without_signature.
81
+ at_xpath("//*[@AssertionID='#{uri[1, uri.size]}']").
82
+ canonicalize(CANON_MODE)
83
+ hash = Base64.encode64(Digest::SHA1.digest(hashed_element)).chomp
84
+ digest_value = ref.xpath('.//xmlns:DigestValue', xmlns: DSIG).text
84
85
 
85
- true
86
+ raise ValidationError, 'Digest mismatch' if hash != digest_value
86
87
  end
88
+ end
89
+
90
+ def validate_signature!(sig_element)
91
+ signed_info_element = sig_element.
92
+ at_xpath('.//xmlns:SignedInfo', xmlns: DSIG).
93
+ canonicalize(CANON_MODE)
94
+ base64_signature = sig_element.xpath('.//xmlns:SignatureValue', xmlns: DSIG).text
95
+ signature = Base64.decode64(base64_signature)
87
96
 
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?
97
+ unless certificate.public_key.verify(OpenSSL::Digest::SHA1.new, signature, signed_info_element)
98
+ raise ValidationError, 'Key validation error'
91
99
  end
92
100
  end
93
101
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-latvija
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edgars Beigarts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-11 00:00:00.000000000 Z
11
+ date: 2017-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: omniauth
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: canonix
28
+ name: xmlenc
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.5.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.5.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,20 @@ dependencies:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '2.10'
83
+ - !ruby/object:Gem::Dependency
84
+ name: byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: simplecov
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -106,6 +134,7 @@ files:
106
134
  - lib/omniauth-latvija.rb
107
135
  - lib/omniauth-latvija/version.rb
108
136
  - lib/omniauth/strategies/latvija.rb
137
+ - lib/omniauth/strategies/latvija/decryptor.rb
109
138
  - lib/omniauth/strategies/latvija/response.rb
110
139
  - lib/omniauth/strategies/latvija/signed_document.rb
111
140
  homepage:
@@ -117,9 +146,9 @@ require_paths:
117
146
  - lib
118
147
  required_ruby_version: !ruby/object:Gem::Requirement
119
148
  requirements:
120
- - - ">="
149
+ - - ">"
121
150
  - !ruby/object:Gem::Version
122
- version: '0'
151
+ version: 2.1.0
123
152
  required_rubygems_version: !ruby/object:Gem::Requirement
124
153
  requirements:
125
154
  - - ">="
@@ -127,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
156
  version: '0'
128
157
  requirements: []
129
158
  rubyforge_project:
130
- rubygems_version: 2.4.6
159
+ rubygems_version: 2.6.11
131
160
  signing_key:
132
161
  specification_version: 4
133
162
  summary: Latvija.lv authentication strategy for OmniAuth