authrocket 2.4.1 → 3.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.
@@ -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.0.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
- attr :min_complexity, :min_length, :required_chars
8
+ attr :min_complexity, :min_length
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,12 @@
1
+ module AuthRocket
2
+ class Connection < Resource
3
+ crud :all, :find, :create, :update, :delete
4
+
5
+ belongs_to :realm
6
+
7
+ attr :connection_type
8
+ attr :email_from, :email_from_name, :state
9
+ attr :smtp_host, :smtp_password, :smtp_port, :smtp_user
10
+
11
+ end
12
+ 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,39 @@
1
+ module AuthRocket
2
+ class Hook < Resource
3
+ crud :all, :find, :create, :update, :delete
4
+
5
+ belongs_to :realm
6
+
7
+ attr :accumulate, :delay, :event_type, :hook_type, :state
8
+ attr :destination
9
+ attr :email_renderer, :email_subject, :email_template, :email_to
10
+
11
+
12
+ def self.event_types
13
+ %w( invitation.org.created invitation.org.updated invitation.org.invited invitation.org.accepted invitation.org.expired
14
+ invitation.referral.created invitation.referral.updated invitation.referral.invited invitation.referral.accepted invitation.referral.expired
15
+ invitation.request.created invitation.request.updated invitation.request.invited invitation.request.accepted invitation.request.expired
16
+ membership.created membership.updated membership.deleted
17
+ org.created org.updated org.closed
18
+ user.created user.updated user.deleted
19
+ user.email.verifying user.email.verified
20
+ user.login.succeeded user.login.failed user.login.initiated
21
+ user.password.resetting user.password.updated
22
+ user.profile.updated
23
+ ).sort
24
+ end
25
+
26
+ def self.email_event_types
27
+ %w( invitation.org.invited invitation.org.accepted
28
+ invitation.referral.invited
29
+ invitation.request.invited
30
+ user.created
31
+ user.email.verifying user.email.verified
32
+ user.login.succeeded user.login.failed
33
+ user.password.resetting user.password.updated
34
+ user.profile.updated
35
+ ).sort
36
+ end
37
+
38
+ end
39
+ 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, :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,18 @@
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
-
14
- def require_valid_token
13
+ def require_login
15
14
  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])}"
15
+ redirect_to ar_login_url(redirect_uri: safe_this_uri)
18
16
  end
19
17
  end
20
18
 
@@ -24,24 +22,78 @@ module AuthRocket::ControllerHelper
24
22
  end
25
23
 
26
24
  def current_user
27
- current_session.try(:user)
25
+ current_session&.user
26
+ end
27
+
28
+ def current_membership
29
+ # LR always sends a JWT with exactly one membership/org
30
+ # other API generated JWTs may vary
31
+ return unless current_user
32
+ current_user.memberships.each{|m| return m if m.selected }.first
33
+ end
34
+
35
+ def current_org
36
+ current_membership&.org
37
+ end
38
+
39
+
40
+ def ar_account_url(**params)
41
+ if id = params.delete(:id) || current_org&.id
42
+ loginrocket_url(path: "/accounts/#{id}", **params)
43
+ else
44
+ ar_accounts_url(**params)
45
+ end
46
+ end
47
+
48
+ # force - if false/nil, does not add ?force; else does add it
49
+ def ar_accounts_url(**params)
50
+ if params[:force] || !params.key?(:force)
51
+ params[:force] = nil
52
+ else
53
+ params.delete(:force)
54
+ end
55
+ loginrocket_url(path: '/accounts', **params)
56
+ end
57
+
58
+ def ar_login_url(**params)
59
+ loginrocket_url(path: '/login', **params)
28
60
  end
29
61
 
62
+ def ar_logout_url(**params)
63
+ params[:session] = current_session.id if current_session
64
+ loginrocket_url(path: '/logout', **params)
65
+ end
30
66
 
31
- def ar_login_url
32
- @_login_url = loginrocket_url('login')
67
+ def ar_profile_url(**params)
68
+ loginrocket_url(path: '/profile', **params)
33
69
  end
34
70
 
35
- def ar_signup_url
36
- @_signup_url = loginrocket_url('signup')
71
+ def ar_signup_url(**params)
72
+ loginrocket_url(path: '/signup', **params)
73
+ end
74
+
75
+ def loginrocket_url(path: nil, **params)
76
+ raise "Missing env LOGINROCKET_URL or credentials[:loginrocket_url]" if AuthRocket::Api.credentials[:loginrocket_url].blank?
77
+ uri = Addressable::URI.parse AuthRocket::Api.credentials[:loginrocket_url]
78
+ uri.path = path if path
79
+ uri.path = '/' if uri.path.blank?
80
+ uri.query_values = (uri.query_values||{}).merge(params).stringify_keys if params.present?
81
+ uri.to_s
82
+ end
83
+
84
+
85
+ # returns: bool -- whether session was updated/replaced
86
+ def conditional_login
87
+ return unless params[:token]
88
+ if s = AuthRocket::Session.from_token(params[:token])
89
+ @_current_session = s
90
+ session[:ar_token] = params[:token]
91
+ true
92
+ end
37
93
  end
38
94
 
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
95
+ def safe_this_uri
96
+ full_url_for(request.get? ? params.to_unsafe_h.except(:account, :session, :token) : {})
45
97
  end
46
98
 
47
99
  end