omniauth-gov 0.1.11 → 0.1.12

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
  SHA256:
3
- metadata.gz: 0762ec72d9f4a09215996f0a976efe561ba960568728c3a803c64e141852698d
4
- data.tar.gz: a7e263a4b7eeb3e2af8cdec1963e64af6f1a5d80c9c59dc099eebf642b3a17ca
3
+ metadata.gz: c8265c888e68097f0365602aded836833501a2d28d0a31458e6349f12a2388c1
4
+ data.tar.gz: 8a1fa392ec58679497e184d918b8e2ed174f902f95c8ad1950f6393042213e34
5
5
  SHA512:
6
- metadata.gz: 620365eaf53aad3f1c1cfa3575eacd2ded1dd5f654a3ec7568a8692a450216eef63d5e8eb1286bd086421c0bf8571301fd30d56c902ed7258be990e4883d6a01
7
- data.tar.gz: e4f670989eeb1448965ed10b4e11a72ca7aa67ebfc5ed32cc504e917eb4d80cade903f46111494f8856fdb948adad93a8494c5b5d76493add15e158f650fe24e
6
+ metadata.gz: f055d36ad468a15d02625f0b57c15cdc7f370b6cf889baa7bfb7e3c32503d54a0c9158bc08e24c373a600e34cd81fce541d1e77f783e0b67445317a9117dfd7f
7
+ data.tar.gz: 68f49eca1cf822ad808877620c5a63bfcc4c276a6c465b98390afda97e41c223bda5be585484017506038927b69c0b852327f8c3513a592891d3a50a6cb9c257
data/LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2011 Michael Bleigh and Intridea, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,144 @@
1
+ ![Ruby](https://github.com/omniauth/omniauth-gov/workflows/Ruby/badge.svg?branch=main)
2
+
3
+ # OmniAuth Gov
4
+
5
+ Estratégia omniauth para integração do Login Único do governo brasileiro ao autentiador devise.
6
+
7
+ ## Instalação
8
+
9
+ ```ruby
10
+ gem 'omniauth', '1.9.1'
11
+ gem "omniauth-rails_csrf_protection", '0.1.2'
12
+ gem 'omniauth-oauth2'
13
+ gem 'omniauth-gov', '~> 0.1.5'
14
+ ```
15
+
16
+ ## Configuração devise
17
+
18
+ Em `config/initializers/devise.rb.rb`
19
+
20
+ ```ruby
21
+ Devise.setup do |config|
22
+ # ...
23
+ config.omniauth :gov,
24
+ ENV['client_id'],
25
+ ENV['client_secret'],
26
+ scope: 'openid+email+profile+govbr_confiabilidades+',
27
+ callback_path: '/callback-da-aplicacao',
28
+ client_options: {
29
+ site: 'https://sso.acesso.gov.br', # Ambiente de produção.
30
+ authorize_url: 'https://sso.acesso.gov.br/authorize', # Ambiente de produção.
31
+ token_url: 'https://sso.acesso.gov.br/token' # Ambiente de produção.
32
+ }
33
+
34
+ config.omniauth_path_prefix = '/prefixo-devise/prefixo-omniauth'
35
+ end
36
+ ```
37
+
38
+ ## Initializer
39
+ Em `config/initializer/omniauth.rb`
40
+
41
+ ```ruby
42
+ OmniAuth.config.full_host = "https://endereco-do-app.gov.br"
43
+ OmniAuth.config.logger = Rails.logger
44
+ ```
45
+
46
+ ## Route
47
+ Em `config/routes.rb`
48
+ ```ruby
49
+ # ...
50
+ devise_for :users, controllers: {
51
+ # ...
52
+ :omniauth_callbacks => 'auth/omniauth_callbacks'
53
+ }
54
+
55
+ # opcional: redirecionar url de callback para o callback do devise
56
+ devise_scope :user do
57
+ get 'url-de-callback', to: 'auth/omniauth_callbacks#gov'
58
+ end
59
+
60
+ ```
61
+
62
+ ## Controller
63
+ Em `controllers/auth/omniauth_callbacks_controller.rb`
64
+
65
+ ```ruby
66
+ # frozen_string_literal: true
67
+
68
+ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
69
+ skip_before_action :verify_authenticity_token
70
+
71
+ def gov
72
+ @user = User.from_gov_br_omniauth(request.env["omniauth.auth"]["info"])
73
+
74
+ if @user.id.present?
75
+ sign_in_and_redirect @user, :event => :authentication
76
+ set_flash_message(:notice, :success, :kind => "Login Unico") if is_navigational_format?
77
+ else
78
+ end
79
+ end
80
+
81
+ def failure
82
+ redirect_to root_path
83
+ end
84
+
85
+ end
86
+ ```
87
+
88
+ ## Model User
89
+ Em `model/user.rb`
90
+ ```ruby
91
+ devise :database_authenticatable,
92
+ # ...
93
+ :omniauthable, omniauth_providers: %i[gov]
94
+
95
+ # ...
96
+ def self.from_gov_br_omniauth(info)
97
+ # Exemplo hash info
98
+ # {
99
+ # "id": 1702579345,
100
+ # "cpf": '99999999999',
101
+ # "nome_social": 'Nome Social',
102
+ # "email_verified": true,
103
+ # "profile": 'https://servicos.staging.acesso.gov.br/',
104
+ # "username": '99999999999',
105
+ # "picture": raw_info["picture"],
106
+ # "name": raw_info["name"],
107
+ # "email": raw_info["email"],
108
+ # }
109
+ user = User.find_by_email(info["email"]) # ou outra chave
110
+
111
+ unless user.nil?
112
+ user.update_attributes(provider: 'login-unico', uid: info["id"])
113
+ else
114
+ name = info["name"]
115
+ email = info["email"]
116
+ user = User.new do |user|
117
+ user.name = name
118
+ user.email = email
119
+ end
120
+ user.skip_confirmation!
121
+ user.save
122
+ end
123
+
124
+ return user
125
+ end
126
+
127
+ ```
128
+
129
+ ## View
130
+ Em `sessions/new.html.erb`
131
+ ```ruby
132
+ <%= button_to omniauth_authorize_path(resource_name, :gov), class: 'gov-br-btn sign-in br-button middle sign-in w-100 is-primary mt-3 mb-3', data: { turbo: false } do %>
133
+ <i class="icon fa fa-user fa-lg" style="color: rgb(255, 255, 255);"></i>&nbsp;
134
+ <span style="font-weight: normal;">Entrar com</span>&nbsp;
135
+ <span style="font-size: 20px; font-weight: bold;"> gov.br</span>
136
+ <% end %>
137
+ ```
138
+
139
+ ## Licença
140
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
141
+
142
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
143
+
144
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GovBr
4
+ # FlatParamsEncoder manages URI params as a flat hash. Any Array values repeat
5
+ # the parameter multiple times.
6
+ module ParamsEncoder
7
+ class << self
8
+ extend Forwardable
9
+ def_delegators :'Faraday::Utils', :escape, :unescape
10
+ end
11
+
12
+ # Encode converts the given param into a URI querystring. Keys and values
13
+ # will converted to strings and appropriately escaped for the URI.
14
+ #
15
+ # @param params [Hash] query arguments to convert.
16
+ #
17
+ # @example
18
+ #
19
+ # encode({a: %w[one two three], b: true, c: "C"})
20
+ # # => 'a=one&a=two&a=three&b=true&c=C'
21
+ #
22
+ # @return [String] the URI querystring (without the leading '?')
23
+ def self.encode(params)
24
+ return nil if params.nil?
25
+
26
+ unless params.is_a?(Array)
27
+ unless params.respond_to?(:to_hash)
28
+ raise TypeError,
29
+ "Can't convert #{params.class} into Hash."
30
+ end
31
+ params = params.to_hash
32
+ params = params.map do |key, value|
33
+ key = key.to_s if key.is_a?(Symbol)
34
+ [key, value]
35
+ end
36
+
37
+ # Only to be used for non-Array inputs. Arrays should preserve order.
38
+ params.sort! if @sort_params
39
+ end
40
+
41
+ # The params have form [['key1', 'value1'], ['key2', 'value2']].
42
+ buffer = +''
43
+ params.each do |key, value|
44
+ encoded_key = escape(key)
45
+ if value.nil?
46
+ buffer << "#{encoded_key}&"
47
+ elsif value.is_a?(Array)
48
+ if value.empty?
49
+ buffer << "#{encoded_key}=&"
50
+ else
51
+ value.each do |sub_value|
52
+ encoded_value = escape(sub_value)
53
+ buffer << "#{encoded_key}=#{encoded_value}&"
54
+ end
55
+ end
56
+ else
57
+ encoded_value = (key == 'scope') ? value : escape(value)
58
+ buffer << "#{encoded_key}=#{encoded_value}&"
59
+ end
60
+ end
61
+ buffer.chop
62
+ end
63
+
64
+ # Decode converts the given URI querystring into a hash.
65
+ #
66
+ # @param query [String] query arguments to parse.
67
+ #
68
+ # @example
69
+ #
70
+ # decode('a=one&a=two&a=three&b=true&c=C')
71
+ # # => {"a"=>["one", "two", "three"], "b"=>"true", "c"=>"C"}
72
+ #
73
+ # @return [Hash] parsed keys and value strings from the querystring.
74
+ def self.decode(query)
75
+ return nil if query.nil?
76
+
77
+ empty_accumulator = {}
78
+
79
+ split_query = (query.split('&').map do |pair|
80
+ pair.split('=', 2) if pair && !pair.empty?
81
+ end).compact
82
+ split_query.each_with_object(empty_accumulator.dup) do |pair, accu|
83
+ pair[0] = unescape(pair[0])
84
+ pair[1] = true if pair[1].nil?
85
+ if pair[1].respond_to?(:to_str)
86
+ pair[1] = unescape(pair[1].to_str.tr('+', ' '))
87
+ end
88
+ if accu[pair[0]].is_a?(Array)
89
+ accu[pair[0]] << pair[1]
90
+ elsif accu[pair[0]]
91
+ accu[pair[0]] = [accu[pair[0]], pair[1]]
92
+ else
93
+ accu[pair[0]] = pair[1]
94
+ end
95
+ end
96
+ end
97
+
98
+ class << self
99
+ attr_accessor :sort_params
100
+ end
101
+
102
+ # Useful default for OAuth and caching.
103
+ @sort_params = true
104
+ end
105
+ end
@@ -0,0 +1,134 @@
1
+ # lib/omniauth/strategies/gov.rb
2
+ require 'omniauth-oauth2'
3
+ require "uri"
4
+
5
+ module OmniAuth
6
+ module Strategies
7
+ class Gov < OmniAuth::Strategies::OAuth2
8
+ option :name, 'gov'
9
+ option :pkce, true
10
+
11
+ credentials do
12
+ hash = {"access_token" => access_token.token}
13
+ hash["id_token"] = access_token.params["id_token"]
14
+ hash["refresh_token"] = access_token.refresh_token if access_token.expires? && access_token.refresh_token
15
+ hash["expires_at"] = access_token.expires_at if access_token.expires?
16
+ hash["expires"] = access_token.expires?
17
+ hash
18
+ end
19
+
20
+ info do
21
+ prune!({
22
+ "id": raw_info['auth_time'],
23
+ "cpf": raw_info["sub"],
24
+ "nome_social": raw_info["social_name"],
25
+ "email_verified": raw_info["email_verified"],
26
+ "profile": raw_info["profile"],
27
+ "username": raw_info["preferred_username"],
28
+ "picture": raw_info["picture"],
29
+ "name": raw_info["name"],
30
+ "email": raw_info["email"],
31
+ })
32
+ end
33
+
34
+ uid { raw_info['auth_time'] }
35
+
36
+ extra do
37
+ {
38
+ 'raw_info': raw_info
39
+ }
40
+ end
41
+
42
+ def client
43
+ options.client_options.merge!({connection_opts: {request: {params_encoder: GovBr::ParamsEncoder}}})
44
+ ::OAuth2::Client.new(options.client_id, options.client_secret, deep_symbolize(options.client_options))
45
+ end
46
+
47
+ def request_phase
48
+ redirect client.auth_code.authorize_url({:redirect_uri => callback_url}.merge(authorize_params))
49
+ end
50
+
51
+ def raw_info
52
+ @raw_info ||= JWT.decode(credentials["id_token"], nil, false)[0]
53
+ end
54
+
55
+ def prune!(hash)
56
+ hash.delete_if do |_, value|
57
+ prune!(value) if value.is_a?(Hash)
58
+ value.nil? || (value.respond_to?(:empty?) && value.empty?)
59
+ end
60
+ end
61
+
62
+ def authorize_params # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
63
+ options.authorize_params[:state] = SecureRandom.hex(24)
64
+ options.authorize_params[:client_id] = options[:client_id]
65
+ options.authorize_params[:scope] = options[:scope]
66
+ options.authorize_params[:response_type] = 'code'
67
+ options.authorize_params[:nonce] = SecureRandom.hex[0..11]
68
+ params = options.authorize_params
69
+ .merge(options_for("authorize"))
70
+ .merge(pkce_authorize_params)
71
+
72
+ session["omniauth.pkce.verifier"] = options.pkce_verifier if options.pkce
73
+ session["omniauth.state"] = params[:state]
74
+
75
+ params
76
+ end
77
+
78
+ def callback_url
79
+ full_host = OmniAuth.config.full_host
80
+ callback_path = options.callback_path
81
+ normalize_url(full_host+callback_path)
82
+ end
83
+
84
+ def normalize_url(url, force_https: true, strip_trailing_slash: true)
85
+ url = url.strip
86
+
87
+ # Adiciona protocolo se não existir
88
+ url = "http://#{url}" unless url =~ %r{^https?://}i
89
+
90
+ begin
91
+ uri = URI.parse(url)
92
+
93
+ # Força HTTPS se habilitado
94
+ uri.scheme = force_https ? "https" : (uri.scheme || "http")
95
+
96
+ # Normaliza host
97
+ uri.host = uri.host.downcase if uri.host
98
+
99
+ # Normaliza path:
100
+ if uri.path
101
+ # Troca // repetidos por /
102
+ uri.path = uri.path.gsub(%r{/+}, "/")
103
+ # Remove barra final se configurado (mas não no caso de root "/")
104
+ if strip_trailing_slash && uri.path != "/" && uri.path.end_with?("/")
105
+ uri.path = uri.path.chomp("/")
106
+ end
107
+ end
108
+
109
+ # Ordena query params (se houver)
110
+ if uri.query
111
+ query_params = URI.decode_www_form(uri.query).uniq.sort
112
+ uri.query = URI.encode_www_form(query_params)
113
+ end
114
+
115
+ uri.to_s
116
+ rescue URI::InvalidURIError
117
+ nil
118
+ end
119
+ end
120
+
121
+ def build_access_token
122
+ verifier = request.params["code"]
123
+
124
+ atoken = client.auth_code.get_token(
125
+ verifier,
126
+ {"grant_type": "authorization_code", "code": verifier, "redirect_uri": callback_url, "code_verifier": session["omniauth.pkce.verifier"]},
127
+ {"Content-Type" => "application/x-www-form-urlencoded", "Authorization" => "Basic #{Base64.strict_encode64(options.client_id+":"+options.client_secret)}" })
128
+ atoken
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ OmniAuth.config.add_camelization 'gov', 'Gov'
@@ -0,0 +1,5 @@
1
+ module OmniAuth
2
+ module Gov
3
+ VERSION = "0.1.12"
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ require "omniauth-gov/version"
2
+ require 'gov_br/params_encoder'
3
+ require 'omniauth/strategies/gov'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-gov
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Ricardo
@@ -137,7 +137,13 @@ email:
137
137
  executables: []
138
138
  extensions: []
139
139
  extra_rdoc_files: []
140
- files: []
140
+ files:
141
+ - LICENSE.txt
142
+ - README.md
143
+ - lib/gov_br/params_encoder.rb
144
+ - lib/omniauth-gov.rb
145
+ - lib/omniauth-gov/version.rb
146
+ - lib/omniauth/strategies/gov.rb
141
147
  homepage: https://github.com/jonasrscampos/omniauth-gov
142
148
  licenses:
143
149
  - MIT