authrocket 2.4.1 → 3.3.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.
@@ -5,7 +5,7 @@ module AuthRocket
5
5
  module ClassMethods
6
6
 
7
7
  def parse_credentials(creds)
8
- creds.with_indifferent_access.except :loginrocket_url, :jwt_secret
8
+ creds.with_indifferent_access.except :loginrocket_url, :jwt_key
9
9
  end
10
10
 
11
11
  end
@@ -1,3 +1,3 @@
1
1
  module AuthRocket
2
- VERSION = '2.4.1'
2
+ VERSION = '3.3.0'
3
3
  end
@@ -5,68 +5,67 @@ module AuthRocket
5
5
  belongs_to :realm
6
6
 
7
7
  attr :name, :provider_type, :state
8
- attr :email_verification, :login, :name_field, :password_field, :signup, :signup_mode, :verify
9
8
  attr :min_complexity, :min_length, :required_chars
10
9
  attr :client_id, :client_secret, :scopes
10
+ attr :loginrocket_domain
11
+ attr :authorization_url, :profile_url, :token_url
12
+ attr :email_field, :email_verified_field, :first_name_field, :id_field, :last_name_field, :name_field
13
+ attr :auth_url # readonly
11
14
 
12
15
 
13
- # attribs - :redirect_uri - required
14
- # - :nonce - optional
15
- def self.authorize_urls(attribs={})
16
- params = parse_request_params(attribs)
17
- parsed, creds = request(:get, url+'/authorize', params)
18
- if parsed[:errors].any?
19
- raise Error, parsed[:errors].inspect
20
- end
21
- NCore::Collection.new.tap do |coll|
22
- coll.metadata = parsed[:metadata]
23
- parsed[:data].each do |hash|
24
- coll << GenericObject.new(hash.merge(metadata: parsed[:metadata]), creds)
25
- end
26
- end
27
- end
28
-
29
- # attribs - :redirect_uri - required
30
- # - :nonce - optional
31
- def self.authorize_url(auth_provider_id, attribs={})
32
- params = parse_request_params(attribs)
33
- parsed, creds = request(:get, url+"/#{auth_provider_id}/authorize", params)
34
- if parsed[:errors].any?
35
- raise Error, parsed[:errors].inspect
36
- end
37
- parsed[:data][:url]
38
- end
39
-
40
16
  # same as self.authorize_url(self.id, ...)
41
17
  def authorize_url(attribs={})
42
- params = parse_request_params(attribs).merge credentials: api_creds
43
- self.class.authorize_url(id, params)
44
- end
45
-
46
- # attribs - :code - required
47
- # - :nonce - optional
48
- # - :state - required
49
- # always returns a new object; check .errors? or .valid? to see how it went
50
- def self.authorize(attribs={})
51
- params = parse_request_params(attribs)
52
- parsed, creds = request(:post, url+'/authorize', params)
53
- if parsed[:data][:object] == 'user_token'
54
- UserToken.new(parsed, creds)
55
- else
56
- User.new(parsed, creds)
57
- end
18
+ self.class.authorize_url id, attribs.reverse_merge(credentials: api_creds)
58
19
  end
59
20
 
60
21
  # attribs - :access_token - required
22
+ # returns: Session
61
23
  # always returns a new object; check .errors? or .valid? to see how it went
62
24
  def authorize_token(attribs={})
63
25
  params = parse_request_params(attribs)
64
- parsed, creds = request(:post, url+'/authorize', params)
65
- if parsed[:data][:object] == 'user_token'
66
- UserToken.new(parsed, creds)
67
- else
68
- User.new(parsed, creds)
26
+ parsed, creds = request(:post, resource_path+'/authorize', params)
27
+ self.class.factory(parsed, creds)
28
+ end
29
+
30
+
31
+ class << self
32
+
33
+ # attribs - :redirect_uri - required
34
+ # - :nonce - optional
35
+ # returns: Array of simplified AuthProviders
36
+ def authorize_urls(attribs={})
37
+ params = parse_request_params(attribs)
38
+ parsed, creds = request(:get, resource_path+'/authorize', params)
39
+ raise QueryError, parsed[:errors] if parsed[:errors].any?
40
+ NCore::Collection.new.tap do |coll|
41
+ coll.metadata = parsed[:metadata]
42
+ parsed[:data].each do |hash|
43
+ coll << factory(hash.merge(metadata: parsed[:metadata]), creds)
44
+ end
45
+ end
46
+ end
47
+
48
+ # attribs - :redirect_uri - required
49
+ # - :nonce - optional
50
+ # returns: simplified AuthProvider
51
+ def authorize_url(auth_provider_id, attribs={})
52
+ params = parse_request_params(attribs)
53
+ parsed, creds = request(:get, resource_path+"/#{CGI.escape auth_provider_id}/authorize", params)
54
+ raise QueryError, parsed[:errors] if parsed[:errors].any?
55
+ factory(parsed, creds)
69
56
  end
57
+
58
+ # attribs - :code - required
59
+ # - :nonce - optional
60
+ # - :state - required
61
+ # returns: Session
62
+ # always returns a new object; check .errors? or .valid? to see how it went
63
+ def authorize(attribs={})
64
+ params = parse_request_params(attribs)
65
+ parsed, creds = request(:post, resource_path+'/authorize', params)
66
+ factory(parsed, creds)
67
+ end
68
+
70
69
  end
71
70
 
72
71
  end
@@ -0,0 +1,14 @@
1
+ module AuthRocket
2
+ class ClientApp < Resource
3
+ crud :all, :find, :create, :update, :delete
4
+
5
+ belongs_to :realm
6
+
7
+ attr :client_type, :name, :redirect_uris
8
+ # standard:
9
+ attr :state
10
+ # oauth2:
11
+ attr :allowed_scopes, :app_type, :logo, :secret, :trusted
12
+
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module AuthRocket
2
+ class Connection < Resource
3
+ crud :all, :find, :create, :update, :delete
4
+
5
+ belongs_to :realm
6
+
7
+ attr :connection_name, :connection_type, :state
8
+ attr :email_from, :email_from_name
9
+ attr :smtp_host, :smtp_password, :smtp_port, :smtp_user
10
+ attr :api_endpoint, :provider_account, :valid_list_ids
11
+
12
+ end
13
+ end
@@ -3,19 +3,25 @@ module AuthRocket
3
3
  crud :find, :create, :update, :delete
4
4
 
5
5
  belongs_to :auth_provider
6
+ belongs_to :client_app
6
7
  belongs_to :user
7
8
 
8
9
  attr :credential_type
9
- attr :api_key
10
- attr :password, :password_confirmation
11
- attr :name, :otp_secret, :provisioning_uri, :state
12
- attr :access_token, :provider_user_id, :token_expires_at
10
+ attr :password, :password_confirmation # writeonly
11
+ attr :name, :otp_secret, :provisioning_svg, :provisioning_uri, :state
12
+ attr :access_token, :provider_user_id
13
+ attr_datetime :token_expires_at
14
+ attr :client_app_name, :approved_scopes
13
15
 
14
16
 
17
+ def provisioning_svg
18
+ self[:provisioning_svg]&.html_safe
19
+ end
20
+
15
21
  # code - required
16
22
  def verify(code, attribs={})
17
- params = parse_request_params(attribs.merge(code: code), json_root: json_root).merge credentials: api_creds
18
- parsed, _ = request(:post, url+'/verify', params)
23
+ params = parse_request_params(attribs.merge(code: code), json_root: json_root).reverse_merge credentials: api_creds
24
+ parsed, _ = request(:post, resource_path+'/verify', params)
19
25
  load(parsed)
20
26
  errors.empty? ? self : false
21
27
  end
@@ -0,0 +1,19 @@
1
+ module AuthRocket
2
+ class Domain < Resource
3
+ crud :all, :find, :create, :update, :delete
4
+
5
+ belongs_to :realm
6
+
7
+ attr :cert_state, :dns_state, :domain_type, :flags, :fqdn, :state
8
+ attr :subdomain
9
+ attr :domain
10
+
11
+ def verify(attribs={})
12
+ params = parse_request_params(attribs, json_root: json_root).reverse_merge credentials: api_creds
13
+ parsed, _ = request(:post, resource_path+'/verify', params)
14
+ load(parsed)
15
+ errors.empty? ? self : false
16
+ end
17
+
18
+ end
19
+ end
@@ -2,16 +2,15 @@ module AuthRocket
2
2
  class Event < Resource
3
3
  crud :all, :find
4
4
 
5
- belongs_to :app_hook
6
5
  belongs_to :auth_provider
7
- belongs_to :login_policy
6
+ belongs_to :invitation
8
7
  belongs_to :membership
9
8
  belongs_to :org
10
9
  belongs_to :realm
11
10
  belongs_to :user
12
11
  has_many :notifications
13
12
 
14
- attr :event_type
13
+ attr :event_type, :token
15
14
  attr_datetime :event_at
16
15
 
17
16
  def request_data
@@ -0,0 +1,42 @@
1
+ module AuthRocket
2
+ class Hook < Resource
3
+ crud :all, :find, :create, :update, :delete
4
+
5
+ belongs_to :realm
6
+ belongs_to :connection
7
+
8
+ attr :accumulate, :delay, :event_type, :hook_type, :state
9
+ attr :destination
10
+ attr :email_renderers, :email_subjects, :email_templates, :email_to, :locales
11
+ attr :current_locales # readonly
12
+ attr :description, :list_id, :name, :on_create, :visibility
13
+
14
+
15
+ def self.event_types
16
+ %w( invitation.org.created invitation.org.updated invitation.org.invited invitation.org.accepted invitation.org.expired
17
+ invitation.referral.created invitation.referral.updated invitation.referral.invited invitation.referral.accepted invitation.referral.expired
18
+ invitation.request.created invitation.request.updated invitation.request.invited invitation.request.accepted invitation.request.expired
19
+ membership.created membership.updated membership.deleted
20
+ org.created org.updated org.closed
21
+ user.created user.updated user.deleted
22
+ user.email.verifying user.email.verified
23
+ user.login.succeeded user.login.failed user.login.initiated
24
+ user.password.resetting user.password.updated
25
+ user.profile.updated
26
+ ).sort
27
+ end
28
+
29
+ def self.email_event_types
30
+ %w( invitation.org.invited invitation.org.accepted
31
+ invitation.referral.invited
32
+ invitation.request.invited
33
+ user.created
34
+ user.email.verifying user.email.verified
35
+ user.login.succeeded user.login.failed
36
+ user.password.resetting user.password.updated
37
+ user.profile.updated
38
+ ).sort
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ module AuthRocket
2
+ class HookState < Resource
3
+ crud :all, :find, :create, :update, :delete
4
+
5
+ belongs_to :hook
6
+ belongs_to :user
7
+
8
+ attr :hook_state_type
9
+ attr :list_state
10
+
11
+
12
+ private
13
+
14
+ def create(attribs={})
15
+ if self[:user_id]
16
+ if attribs.key? json_root
17
+ attribs[json_root][:user_id] ||= self[:user_id]
18
+ else
19
+ attribs[:user_id] ||= self[:user_id]
20
+ end
21
+ end
22
+ super attribs
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ module AuthRocket
2
+ class Invitation < Resource
3
+ crud :all, :find, :create, :update, :delete
4
+
5
+ belongs_to :inviting_user, class_name: 'AuthRocket::User'
6
+ belongs_to :org
7
+ belongs_to :realm
8
+ has_many :events
9
+
10
+ attr :email, :invitation_type, :locale, :token
11
+ attr :permissions
12
+ attr_datetime :created_at, :expires_at, :invited_at
13
+
14
+ def any_permission?(*perms)
15
+ perms.any? do |p|
16
+ case p
17
+ when String
18
+ permissions.include? p
19
+ when Regexp
20
+ permissions.any?{|m| p =~ m}
21
+ else
22
+ false
23
+ end
24
+ end
25
+ end
26
+
27
+ def invite(attribs={})
28
+ params = parse_request_params(attribs, json_root: json_root).reverse_merge credentials: api_creds
29
+ parsed, _ = request(:post, resource_path+'/invite', params)
30
+ load(parsed)
31
+ errors.empty? ? self : false
32
+ end
33
+
34
+ end
35
+ end
@@ -6,7 +6,7 @@ module AuthRocket
6
6
  belongs_to :user
7
7
  has_many :events
8
8
 
9
- attr :custom, :permissions
9
+ attr :permissions, :selected
10
10
  attr_datetime :expires_at
11
11
 
12
12
 
@@ -0,0 +1,10 @@
1
+ module AuthRocket
2
+ class NamedPermission < Resource
3
+ crud :find, :create, :update, :delete
4
+
5
+ belongs_to :realm
6
+
7
+ attr :auto_grant, :name, :permission
8
+
9
+ end
10
+ end
@@ -1,8 +1,8 @@
1
1
  module AuthRocket
2
2
  class Notification < Resource
3
3
 
4
- belongs_to :app_hook
5
4
  belongs_to :event
5
+ belongs_to :hook
6
6
 
7
7
  attr :attempts, :hook_type, :last_destination, :last_result, :state
8
8
  attr_datetime :last_attempt_at
@@ -0,0 +1,26 @@
1
+ module AuthRocket
2
+ class Oauth2Session < Resource
3
+ crud :find, :create
4
+
5
+ attr :access_token, :code, :id_token, :redirect_uri
6
+ attr :profile
7
+ attr :expires_in, :token_type
8
+ attr_datetime :expires_at
9
+
10
+ def self.json_root ; 'session' ; end
11
+ def self.resource_path ; 'sessions/oauth2' ; end
12
+
13
+ class << self
14
+
15
+ # params - {client_app_id:, client_app_secret:, code:}
16
+ # returns: Token - must check .valid? or .errors? for response
17
+ def code_to_token(params={})
18
+ params = parse_request_params(params, json_root: json_root)
19
+ parsed, creds = request(:post, "#{resource_path}/code", params)
20
+ factory(parsed, creds)
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
@@ -4,6 +4,7 @@ module AuthRocket
4
4
 
5
5
  belongs_to :realm
6
6
  has_many :events
7
+ has_many :invitations
7
8
  has_many :memberships
8
9
 
9
10
  attr :custom, :name, :reference, :state
@@ -11,7 +12,7 @@ module AuthRocket
11
12
 
12
13
 
13
14
  def users
14
- memberships.map(&:user).compact
15
+ memberships.map(&:user)
15
16
  end
16
17
 
17
18
  def find_user(uid)
@@ -1,20 +1,26 @@
1
1
  module AuthRocket::ControllerHelper
2
2
  extend ActiveSupport::Concern
3
3
 
4
- included do
5
- if respond_to?(:helper_method)
6
- helper_method :current_session
7
- helper_method :current_user
8
- helper_method :ar_login_url
9
- helper_method :ar_signup_url
4
+ private
5
+
6
+ def process_inbound_token
7
+ # if GET (the only method LR uses), redirect to remove ?token=
8
+ if request.get? && conditional_login
9
+ redirect_to safe_this_uri
10
10
  end
11
11
  end
12
12
 
13
+ def process_authorization_header
14
+ if request.headers['authorization'] =~ %r{Bearer (.+)$}i
15
+ if s = AuthRocket::Session.from_token($1)
16
+ @_current_session = s
17
+ end
18
+ end
19
+ end
13
20
 
14
- def require_valid_token
21
+ def require_login
15
22
  unless current_session
16
- session[:last_url] = request.get? ? url_for(params.to_unsafe_h.except(:domain, :host, :port, :prototcol, :subdomain, :token)) : url_for
17
- redirect_to ar_login_url + "?redir=#{ERB::Util.url_encode(session[:last_url])}"
23
+ redirect_to ar_login_url(redirect_uri: safe_this_uri)
18
24
  end
19
25
  end
20
26
 
@@ -24,24 +30,78 @@ module AuthRocket::ControllerHelper
24
30
  end
25
31
 
26
32
  def current_user
27
- current_session.try(:user)
33
+ current_session&.user
34
+ end
35
+
36
+ def current_membership
37
+ # LR always sends a JWT with exactly one membership/org
38
+ # other API generated JWTs may vary
39
+ return unless current_user
40
+ current_user.memberships.each{|m| return m if m.selected }.first
41
+ end
42
+
43
+ def current_org
44
+ current_membership&.org
28
45
  end
29
46
 
30
47
 
31
- def ar_login_url
32
- @_login_url = loginrocket_url('login')
48
+ def ar_account_url(**params)
49
+ if id = params.delete(:id) || current_org&.id
50
+ loginrocket_url(path: "/accounts/#{id}", **params)
51
+ else
52
+ ar_accounts_url(**params)
53
+ end
54
+ end
55
+
56
+ # force - if false/nil, does not add ?force; else does add it
57
+ def ar_accounts_url(**params)
58
+ if params[:force] || !params.key?(:force)
59
+ params[:force] = nil
60
+ else
61
+ params.delete(:force)
62
+ end
63
+ loginrocket_url(path: '/accounts', **params)
33
64
  end
34
65
 
35
- def ar_signup_url
36
- @_signup_url = loginrocket_url('signup')
66
+ def ar_login_url(**params)
67
+ loginrocket_url(path: '/login', **params)
68
+ end
69
+
70
+ def ar_logout_url(**params)
71
+ params[:session] = current_session.id if current_session
72
+ loginrocket_url(path: '/logout', **params)
73
+ end
74
+
75
+ def ar_profile_url(**params)
76
+ loginrocket_url(path: '/profile', **params)
77
+ end
78
+
79
+ def ar_signup_url(**params)
80
+ loginrocket_url(path: '/signup', **params)
81
+ end
82
+
83
+ def loginrocket_url(path: nil, **params)
84
+ raise "Missing env LOGINROCKET_URL or credentials[:loginrocket_url]" if AuthRocket::Api.credentials[:loginrocket_url].blank?
85
+ uri = Addressable::URI.parse AuthRocket::Api.credentials[:loginrocket_url]
86
+ uri.path = path if path
87
+ uri.path = '/' if uri.path.blank?
88
+ uri.query_values = (uri.query_values||{}).merge(params).stringify_keys if params.present?
89
+ uri.to_s
90
+ end
91
+
92
+
93
+ # returns: bool -- whether session was updated/replaced
94
+ def conditional_login
95
+ return unless params[:token]
96
+ if s = AuthRocket::Session.from_token(params[:token])
97
+ @_current_session = s
98
+ session[:ar_token] = params[:token]
99
+ true
100
+ end
37
101
  end
38
102
 
39
- def loginrocket_url(path=nil)
40
- raise "Missing env AUTHROCKET_LOGIN_URL or credentials[:loginrocket_url]" if AuthRocket::Api.credentials[:loginrocket_url].blank?
41
- s = AuthRocket::Api.credentials[:loginrocket_url].dup
42
- s.concat('/') unless s.ends_with?('/')
43
- s.concat(path) if path
44
- s.freeze
103
+ def safe_this_uri
104
+ full_url_for(request.get? ? params.to_unsafe_h.except(:account, :session, :token) : {})
45
105
  end
46
106
 
47
107
  end