omniauth-ruesia 1.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 +7 -0
- data/README.md +59 -0
- data/Rakefile +3 -0
- data/lib/oauth2/esia_client.rb +9 -0
- data/lib/oauth2/strategy/esia_auth_code.rb +9 -0
- data/lib/omniauth/strategies/ruesia.rb +149 -0
- data/lib/omniauth-ruesia.rb +5 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1a44cd7dc2ba7c42cfdb0b16d35871d0ff0109c7927b5fae0338d56cc6b63b94
|
4
|
+
data.tar.gz: 15f919a487dd76234cfac35183beb550d5d0a3fb0b518acf07eab19cda184789
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3128af25f1519daea6baf38697e6ee22ae1381b551426672270cd1a587c3a223ac60a0e63a20d5af4e0c75d06b61160e598e107c8870705238d12244b745a2f3
|
7
|
+
data.tar.gz: 216ebba99f9eca7cee7d828a69da9cb23b87d52757c7bb890a42075bc5a5ff25e745de684474c627dab86e1fb50be67ddc7d9d70990ea5a07265fbb770df3743
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Ruesia
|
2
|
+
`OmniAuth::Strategies::Ruesia` is a simple Rack middleware for authorization in the russian Unified identification and authentication system(ЕСИА). Read the OmniAuth docs for detailed instructions: https://github.com/intridea/omniauth. The `…/v2/ac` resource is used as a technical solution for gathering authentication code and `…/v3/te` for JWT. In order to write `client_secret`, you need to send an http post request to any system that can work with data-hash signing algorithms using mechanisms of certified Russian
|
3
|
+
cryptographic means of information protection and a certificate
|
4
|
+
of the information system and return json response with signature
|
5
|
+
```
|
6
|
+
Request:
|
7
|
+
POST /api/sign { test: 'any string' }
|
8
|
+
|
9
|
+
Response:
|
10
|
+
{ signature: 'base64urlsafe signature' }
|
11
|
+
```
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem "ruesia"
|
18
|
+
```
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
```bash
|
22
|
+
$ bundle
|
23
|
+
```
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
```bash
|
27
|
+
$ gem install ruesia
|
28
|
+
```
|
29
|
+
## Usage
|
30
|
+
Here's a quick example, adding the middleware to a Rails app in config/initializers/ruesia.rb:
|
31
|
+
```
|
32
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
33
|
+
provider :ruesia, 'MY_SYSTEM',
|
34
|
+
scope: 'fullname email mobile id_doc'
|
35
|
+
cert_fingerprint: 'cert hex fingerprint'
|
36
|
+
csp_server_url: 'http://192.168.1.195:8080/api/sign'
|
37
|
+
client_options:
|
38
|
+
site: 'https://esia-portal1.test.gosuslugi.ru'
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
## Configuration
|
43
|
+
Guidelines for the use of the Unified Identification and Authentication System:
|
44
|
+
https://digital.gov.ru/ru/documents/6186/
|
45
|
+
|option |comment |
|
46
|
+
|---|---|
|
47
|
+
|scope |requested access rights - paragraph B4 Table 95 |
|
48
|
+
|cert_fingerprint| parameter containing the hash of the certificate (`fingerprint`) of the client system in hex format. To generate it, use http://esia.gosuslugi.ru/public/calc_cert_hash_unix.zip|
|
49
|
+
|csp_server_url| url for cms server. We use Faradat to `post` request for `/api/sign`|
|
50
|
+
|
51
|
+
Add callback request to routes
|
52
|
+
```
|
53
|
+
get 'auth/:provider/callback', to: 'api/client/esia#create'
|
54
|
+
```
|
55
|
+
## Contributing
|
56
|
+
Contribution directions go here.
|
57
|
+
|
58
|
+
## License
|
59
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAuth
|
4
|
+
module Strategies
|
5
|
+
class Ruesia < OmniAuth::Strategies::OAuth2
|
6
|
+
option :name, 'ruesia'
|
7
|
+
option :client_options, {
|
8
|
+
site: 'https://esia.gosuslugi.ru',
|
9
|
+
authorize_url: 'aas/oauth2/v2/ac',
|
10
|
+
token_url: 'aas/oauth2/v3/te',
|
11
|
+
}
|
12
|
+
uid { JWT.decode(access_token.token, nil, false).first['urn:esia:sbj_id'] }
|
13
|
+
|
14
|
+
info do
|
15
|
+
{
|
16
|
+
first_name: raw_info['firstName'],
|
17
|
+
last_name: raw_info['lastName'],
|
18
|
+
middle_name: raw_info['middleName'],
|
19
|
+
truster: raw_info['trusted'],
|
20
|
+
verifying: raw_info['verifying'],
|
21
|
+
r_id_doc: raw_info['r_id_doc'],
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
extra do
|
26
|
+
scopes = options.scope.split
|
27
|
+
extra_ = {}
|
28
|
+
extra_ = extra_.merge(get_email) if scopes.include?('email')
|
29
|
+
extra_ = extra_.merge(get_passport) if scopes.include?('id_doc')
|
30
|
+
extra_ = extra_.merge(get_mobile) if scopes.include?('mobile')
|
31
|
+
extra_
|
32
|
+
end
|
33
|
+
|
34
|
+
def raw_info
|
35
|
+
@raw_info ||= access_token.get("/rs/prns/#{uid}")&.parsed
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def state
|
41
|
+
@state ||= SecureRandom.uuid
|
42
|
+
end
|
43
|
+
|
44
|
+
def authorize_params # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
45
|
+
options.authorize_params[:state] = state
|
46
|
+
|
47
|
+
if OmniAuth.config.test_mode
|
48
|
+
@env ||= {}
|
49
|
+
@env["rack.session"] ||= {}
|
50
|
+
end
|
51
|
+
|
52
|
+
params = options.authorize_params
|
53
|
+
.merge(options_for("authorize"))
|
54
|
+
.merge(pkce_authorize_params)
|
55
|
+
|
56
|
+
session["omniauth.pkce.verifier"] = options.pkce_verifier if options.pkce
|
57
|
+
session["omniauth.state"] = params[:state]
|
58
|
+
|
59
|
+
params
|
60
|
+
end
|
61
|
+
|
62
|
+
def request_phase
|
63
|
+
redirect client.auth_code.authorize_url(
|
64
|
+
authorize_params.merge(
|
65
|
+
redirect_uri: callback_url,
|
66
|
+
timestamp: timestamp,
|
67
|
+
client_certificate_hash: fingerprint,
|
68
|
+
client_secret: sign(client_secret_base)
|
69
|
+
)
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
def client
|
74
|
+
::OAuth2::EsiaClient.new(
|
75
|
+
options.client_id,
|
76
|
+
'',
|
77
|
+
deep_symbolize(options.client_options)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def client_secret_base
|
82
|
+
base_secret = [options.client_id, options.scope, timestamp, state, callback_url]
|
83
|
+
yield base_secret if block_given?
|
84
|
+
|
85
|
+
base_secret.join
|
86
|
+
end
|
87
|
+
|
88
|
+
def timestamp
|
89
|
+
@timestamp ||= Time.current.strftime('%Y.%m.%d %H:%M:%S %z')
|
90
|
+
end
|
91
|
+
|
92
|
+
def fingerprint
|
93
|
+
options.cert_fingerprint
|
94
|
+
end
|
95
|
+
|
96
|
+
def sign(secret)
|
97
|
+
secret_base64 = Base64.urlsafe_encode64(secret)
|
98
|
+
response = Faraday.post(options.csp_server_url, { text: secret_base64 })
|
99
|
+
JSON.parse(response.body)['signature']
|
100
|
+
end
|
101
|
+
|
102
|
+
def build_access_token
|
103
|
+
code = request.params['code']
|
104
|
+
client.auth_code.get_token(code,
|
105
|
+
{
|
106
|
+
state: state,
|
107
|
+
scope: options.scope,
|
108
|
+
timestamp: timestamp,
|
109
|
+
redirect_uri: callback_url,
|
110
|
+
token_type: 'Bearer',
|
111
|
+
client_secret: sign(client_secret_base { |secret| secret << code }),
|
112
|
+
client_id: options.client_id,
|
113
|
+
client_certificate_hash: fingerprint
|
114
|
+
}
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_email
|
119
|
+
{
|
120
|
+
email: ctts.find { |e| e['type'] == 'EML' }.fetch('value')
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
def get_passport
|
125
|
+
{
|
126
|
+
passport: access_token
|
127
|
+
.get("/rs/prns/#{uid}/docs?embed=(elements)")
|
128
|
+
.parsed.fetch('elements', {})
|
129
|
+
.find { |e| e['type'] == 'RF_PASSPORT' }
|
130
|
+
.to_h
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
def get_mobile
|
135
|
+
{
|
136
|
+
mobile: ctts
|
137
|
+
.find { |e| e['type'] == 'MBT' }
|
138
|
+
.fetch('value')
|
139
|
+
}
|
140
|
+
end
|
141
|
+
|
142
|
+
def ctts
|
143
|
+
@ctts ||= access_token
|
144
|
+
.get("/rs/prns/#{uid}/ctts?embed=(elements)")
|
145
|
+
.parsed.fetch('elements', {})
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omniauth-ruesia
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ''
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-07-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: omniauth
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: omniauth-rails_csrf_protection
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: omniauth-oauth2
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Description of Ruesia.
|
70
|
+
email:
|
71
|
+
- ''
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- lib/oauth2/esia_client.rb
|
79
|
+
- lib/oauth2/strategy/esia_auth_code.rb
|
80
|
+
- lib/omniauth-ruesia.rb
|
81
|
+
- lib/omniauth/strategies/ruesia.rb
|
82
|
+
homepage: https://github.com/vysogota0399/omniauth-ruesia
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata:
|
86
|
+
allowed_push_host: https://rubygems.org
|
87
|
+
homepage_uri: https://github.com/vysogota0399/omniauth-ruesia
|
88
|
+
source_code_uri: https://github.com/vysogota0399/omniauth-ruesia
|
89
|
+
changelog_uri: https://github.com/vysogota0399/omniauth-ruesia/blob/main/CHANGELOG.md
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubygems_version: 3.4.19
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: Summary of Ruesia.
|
109
|
+
test_files: []
|