1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
# frozen_string_literal: true
class Client < ApplicationRecord
RESPONSE_TYPES = %w[code token].freeze
audited
has_secure_password
has_many :authorizations, dependent: :delete_all
attribute :redirect_uris, :string, array: true
enum token_endpoint_auth_method: {
client_secret_basic: 0,
client_secret_post: 1,
client_secret_none: 2,
}
validates :redirect_uris, presence: true
validates :jwks_uri, format: { with: URI_REGEX }, allow_blank: true
validates :logo_uri, format: { with: URI_REGEX }, allow_blank: true
validates :name, presence: true
validates_each :redirect_uris do |record, _attr, value|
invalid_uri = Array(value).find { |x| !x.match?(URI_REGEX) }
record.errors[:redirect_uris] << 'is invalid.' if invalid_uri
end
after_initialize do
self.password = SecureRandom.base58(24) unless password_digest
end
def grant_types
[
:authorization_code,
:refresh_token,
:client_credentials,
:password,
'urn:ietf:params:oauth:grant-type:saml2-bearer'
]
end
def access_token
transaction do
Token
.active.where(subject: self, audience: self)
.update_all(revoked_at: Time.current)
Token.create!(subject: self, audience: self, token_type: :access)
end
end
def revoke(token)
token.revoke! if token.issued_to?(self)
end
def valid_redirect_uri?(redirect_uri)
redirect_uris.include? redirect_uri
end
def valid_response_type?(response_type)
RESPONSE_TYPES.include?(response_type)
end
def redirect_url_for(user, oauth)
sha256 = oauth[:code_challenge_method] == 'S256'
authorization = authorizations.create!(
user: user,
challenge: oauth[:code_challenge],
challenge_method: sha256 ? :sha256 : :plain
)
if oauth[:response_type] == 'code'
redirect_url(code: authorization.code, state: oauth[:state]) do
oauth[:redirect_uri]
end
elsif oauth[:response_type] == 'token'
access_token, = authorization.issue_tokens_to(
self, token_types: [:access]
)
redirect_url(
access_token: access_token.to_jwt,
token_type: 'Bearer',
expires_in: 5.minutes.to_i,
scope: :admin,
state: oauth[:state]
) do
oauth[:redirect_uri]
end
else
redirect_url(error: 'unsupported_response_type', state: state)
end
end
def redirect_url(fragments = {})
redirect_uri = block_given? ? yield : redirect_uris[0]
return unless valid_redirect_uri?(redirect_uri)
URI.parse(
"#{redirect_uri}#" + fragments.map do |(key, value)|
"#{key}=#{value}" if value.present?
end.compact.join("&")
).to_s
end
end
|