authorio 0.8.1 → 0.8.2
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 +4 -4
- data/README.md +25 -0
- data/app/assets/stylesheets/authorio/auth.css +23 -1
- data/app/controllers/authorio/auth_controller.rb +87 -44
- data/app/{controllers/authorio/helpers.rb → helpers/authorio/tag_helper.rb} +3 -3
- data/app/models/authorio/session.rb +40 -0
- data/app/models/authorio/token.rb +8 -0
- data/app/views/authorio/auth/authorization_interface.html.erb +28 -32
- data/app/views/layouts/authorio/main.html.erb +27 -0
- data/config/routes.rb +3 -1
- data/db/migrate/20210723161041_add_expiry_to_tokens.rb +5 -0
- data/db/migrate/20210726164625_create_authorio_sessions.rb +12 -0
- data/lib/authorio/configuration.rb +4 -1
- data/lib/authorio/engine.rb +5 -4
- data/lib/authorio/exceptions.rb +9 -0
- data/lib/authorio/version.rb +1 -1
- data/lib/generators/authorio/install/templates/authorio.rb +9 -0
- metadata +18 -19
- data/app/controllers/authorio/application_controller.rb +0 -4
- data/app/helpers/authorio/application_helper.rb +0 -4
- data/app/helpers/authorio/test_helper.rb +0 -4
- data/app/views/layouts/authorio/application.html.erb +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b69bae6ee41c0e027922f5bc07b2bc61c72c86026a8e42eee97366453858af43
|
|
4
|
+
data.tar.gz: 496cb0ada5d2802e789b34e28ed21dc320b4ce76c9b9036b705ea8f7219efa8a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a361fbec959948621257d111de2af8256fc23fee38be56660c66b5b68b8f80972660317ac06d997c93cd28b62406387089a67110894d09acdf34d60e2b8635c
|
|
7
|
+
data.tar.gz: a887161dd53aedea2527d1678db6fc6cd7c7d22aff6631442cde63d61d4f6093f29c08bcab8ef20c278d255e247eb5fcb8c5be549ced931f81ac2954e8d1c7fe
|
data/README.md
CHANGED
|
@@ -106,6 +106,31 @@ will be logged in!
|
|
|
106
106
|
When you installed Authorio it placed a config file in `config/initializers/authorio.rb`. If you want to change
|
|
107
107
|
one of the defaults you can uncomment it and specify it here.
|
|
108
108
|
|
|
109
|
+
### Mount Point
|
|
110
|
+
|
|
111
|
+
Most Rails engines are mounted via `mount Authorio::Engine, at: mount_point`. But Authorio needs to know its own
|
|
112
|
+
mount point (to specify its url in the header tag) so you specify the mount point here. The default `authorio`
|
|
113
|
+
should work for everyone.
|
|
114
|
+
|
|
115
|
+
### Authorization and Token Endpoint
|
|
116
|
+
|
|
117
|
+
These endpointd are given to servers via discovery. The default values should suffice.
|
|
118
|
+
|
|
119
|
+
### Token Expiration
|
|
120
|
+
|
|
121
|
+
If a client asks for an authentication token, the token will be valid for this length of time, after which
|
|
122
|
+
you will have to re-authenticate. Longer-lasting
|
|
123
|
+
tokens can possibly be a security risk. Default is 4 weeks.
|
|
124
|
+
|
|
125
|
+
### Local Session Lifetime
|
|
126
|
+
|
|
127
|
+
Setting this to a time interval will enable you to authenticate without typing in your password. It enables a
|
|
128
|
+
"remember me" chekbox on the authentication form. If you check that, then enter your
|
|
129
|
+
password once, then your session will be saved in a cookie, and any time you are asked to authenticate again,
|
|
130
|
+
you can just click "Sign In" without your password. It can be a security risk if someone else has access to
|
|
131
|
+
the machine you are using to login with (eg your laptop). Obviously you don't want to check "remember me"
|
|
132
|
+
on a public-access computer. Default is *nil* (disabled)
|
|
133
|
+
|
|
109
134
|
### TODO
|
|
110
135
|
|
|
111
136
|
- [ ] Customizing the authentication view/UI
|
|
@@ -27,7 +27,7 @@ div.authorio-auth {
|
|
|
27
27
|
margin-left: 1.2em;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
.authorio-auth input {
|
|
30
|
+
.authorio-auth input:not([type='checkbox']):not([type='submit']) {
|
|
31
31
|
margin: 0 1em 1em 1em;
|
|
32
32
|
width: 90%;
|
|
33
33
|
}
|
|
@@ -39,3 +39,25 @@ div.authorio-auth {
|
|
|
39
39
|
.authorio-auth input.btn {
|
|
40
40
|
margin-top: 2em;
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
.auth-btn-row {
|
|
44
|
+
margin: 1em;
|
|
45
|
+
width: 90%;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.authorio-auth .auth-btn-row .auth-btn {
|
|
49
|
+
width: 45%;
|
|
50
|
+
margin: 0.1em;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.authorio-auth .auth-btn-row .auth-btn:last-child {
|
|
54
|
+
float: right;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
span.r-m {
|
|
58
|
+
font-weight: 200;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
label.remember {
|
|
62
|
+
margin-top: -1em;
|
|
63
|
+
}
|
|
@@ -2,84 +2,103 @@ module Authorio
|
|
|
2
2
|
class AuthController < ActionController::Base
|
|
3
3
|
require 'uri'
|
|
4
4
|
require 'digest'
|
|
5
|
+
layout 'authorio/main'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
# These API-only endpoints are protected by code challenge and do not need CSRF protextion
|
|
8
|
+
protect_from_forgery with: :exception, except: [:send_profile, :issue_token]
|
|
9
|
+
|
|
10
|
+
rescue_from 'Authorio::Exceptions::SessionReplayAttack' do |exception|
|
|
11
|
+
redirect_back_with_error "Session Replay attack detected. This has been logged."
|
|
12
|
+
logger.info "Session replay attack detected!"
|
|
13
|
+
Authorio::Session.where(user: exception.session.user).delete_all
|
|
14
|
+
end
|
|
7
15
|
|
|
8
16
|
def authorization_interface
|
|
9
17
|
p = auth_req_params
|
|
10
18
|
p[:me] ||= "#{host_with_protocol}/"
|
|
11
|
-
|
|
12
|
-
user = User.find_by! profile_path: URI(p[:me]).path
|
|
13
|
-
@user_url = p[:me] || user_url(user)
|
|
19
|
+
@user = User.find_by! profile_path: URI(p[:me]).path
|
|
14
20
|
|
|
15
21
|
# If there are any old requests from this (client, user), delete them now
|
|
16
|
-
Request.where(authorio_user: user, client: p[:client_id]).delete_all
|
|
22
|
+
Request.where(authorio_user: @user, client: p[:client_id]).delete_all
|
|
17
23
|
|
|
18
24
|
auth_request = Request.new.tap do |req|
|
|
19
25
|
req.code = SecureRandom.hex(20)
|
|
20
26
|
req.redirect_uri = p[:redirect_uri]
|
|
21
27
|
req.client = p[:client_id] # IndieAuth client_id conflicts with Rails' _id foreign key convention
|
|
22
28
|
req.scope = p[:scope]
|
|
23
|
-
req.authorio_user = user
|
|
29
|
+
req.authorio_user = @user
|
|
24
30
|
end
|
|
25
31
|
auth_request.save
|
|
26
32
|
session[:state] = p[:state]
|
|
27
33
|
session[:code_challenge] = p[:code_challenge]
|
|
34
|
+
session[:client_id] = p[:client_id]
|
|
35
|
+
@user_logged_in_locally = !user_session.nil?
|
|
36
|
+
@rememberable = Authorio.configuration.local_session_lifetime && !@user_logged_in_locally
|
|
28
37
|
|
|
29
38
|
rescue ActiveRecord::RecordNotFound
|
|
30
|
-
|
|
31
|
-
redirect_back fallback_location: Authorio.authorization_path, allow_other_host: false
|
|
39
|
+
redirect_back_with_error "Invalid user"
|
|
32
40
|
end
|
|
33
41
|
|
|
34
42
|
def authorize_user
|
|
35
43
|
p = auth_user_params
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
|
|
45
|
+
if params[:commit] == "Cancel"
|
|
46
|
+
redirect_to session[:client_id] and return
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
user = authenticate_user_from_session_or_password
|
|
50
|
+
if p[:remember_me]
|
|
51
|
+
cookies.encrypted[:user] = {
|
|
52
|
+
value: Authorio::Session.create(authorio_user: user).as_cookie,
|
|
53
|
+
expires: Authorio.configuration.local_session_lifetime
|
|
54
|
+
}
|
|
44
55
|
end
|
|
56
|
+
|
|
57
|
+
auth_req = Request.find_by! client: session[:client_id], authorio_user: user
|
|
58
|
+
params = { code: auth_req.code, state: session[:state] }
|
|
59
|
+
redirect_to "#{auth_req.redirect_uri}?#{params.to_query}"
|
|
60
|
+
|
|
45
61
|
rescue ActiveRecord::RecordNotFound
|
|
46
|
-
|
|
47
|
-
|
|
62
|
+
redirect_back_with_error "Invalid user"
|
|
63
|
+
rescue Authorio::Exceptions::InvalidPassword
|
|
64
|
+
redirect_back_with_error "Incorrect password. Try again."
|
|
48
65
|
end
|
|
49
66
|
|
|
50
67
|
def send_profile
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
render invalid_grant
|
|
55
|
-
end
|
|
68
|
+
render json: { 'me': user_url(validate_request.authorio_user) }
|
|
69
|
+
rescue Authorio::Exceptions::InvalidGrant
|
|
70
|
+
render invalid_grant
|
|
56
71
|
end
|
|
57
72
|
|
|
58
73
|
def issue_token
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
end
|
|
74
|
+
req = validate_request
|
|
75
|
+
raise Authorio::Exceptions::InvalidGrant.new if req.scope.blank?
|
|
76
|
+
token = Token.create(authorio_user: req.authorio_user, scope: req.scope, client: req.client)
|
|
77
|
+
render json: {
|
|
78
|
+
'me': user_url(req.authorio_user),
|
|
79
|
+
'access_token': token.auth_token,
|
|
80
|
+
'scope': req.scope,
|
|
81
|
+
'expires_in': Authorio.configuration.token_expiration,
|
|
82
|
+
'token_type': 'Bearer'
|
|
83
|
+
}
|
|
84
|
+
rescue Authorio::Exceptions::InvalidGrant
|
|
85
|
+
render invalid_grant
|
|
72
86
|
end
|
|
73
87
|
|
|
74
88
|
def verify_token
|
|
75
89
|
token = Token.find_by! auth_token: bearer_token
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
if token.expired?
|
|
91
|
+
token.delete
|
|
92
|
+
render token_expired
|
|
93
|
+
else
|
|
94
|
+
render json: {
|
|
95
|
+
'me': user_url(token.authorio_user),
|
|
96
|
+
'client_id': token.client,
|
|
97
|
+
'scope': 'token.scope'
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
rescue ActiveRecord::RecordNotFound
|
|
101
|
+
head :bad_request
|
|
83
102
|
end
|
|
84
103
|
|
|
85
104
|
private
|
|
@@ -94,7 +113,7 @@ module Authorio
|
|
|
94
113
|
end
|
|
95
114
|
|
|
96
115
|
def auth_user_params
|
|
97
|
-
params.permit(:password, :url, :
|
|
116
|
+
params.require(:user).permit(:password, :url, :remember_me)
|
|
98
117
|
end
|
|
99
118
|
|
|
100
119
|
def host_with_protocol
|
|
@@ -109,6 +128,10 @@ module Authorio
|
|
|
109
128
|
{ json: { 'error': 'invalid_grant' }, status: :bad_request }
|
|
110
129
|
end
|
|
111
130
|
|
|
131
|
+
def token_expired
|
|
132
|
+
{ json: {'error': 'invalid_token', 'error_message': 'The access token has expired' }, status: :unauthorized }
|
|
133
|
+
end
|
|
134
|
+
|
|
112
135
|
def code_challenge_failed?
|
|
113
136
|
# For now, if original request did not have code challenge, then we pass by default
|
|
114
137
|
return false if session[:code_challenge].nil?
|
|
@@ -137,5 +160,25 @@ module Authorio
|
|
|
137
160
|
header.gsub(bearer, '') if header && header.match(bearer)
|
|
138
161
|
end
|
|
139
162
|
|
|
163
|
+
def user_session
|
|
164
|
+
cookie = cookies.encrypted[:user] and Session.find_by_cookie(cookie)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def redirect_back_with_error(error)
|
|
168
|
+
flash[:alert] = error
|
|
169
|
+
redirect_back fallback_location: Authorio.authorization_path, allow_other_host: false
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def authenticate_user_from_session_or_password
|
|
173
|
+
session = user_session
|
|
174
|
+
if session
|
|
175
|
+
return session.authorio_user
|
|
176
|
+
else
|
|
177
|
+
user = User.find_by! profile_path: URI(auth_user_params[:url]).path
|
|
178
|
+
raise Authorio::Exceptions::InvalidPassword unless user.authenticate(auth_user_params[:password])
|
|
179
|
+
return user
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
140
183
|
end
|
|
141
184
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Authorio
|
|
2
2
|
# These helpers are provided to the main application
|
|
3
|
-
module
|
|
3
|
+
module TagHelper
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
6
|
included do
|
|
@@ -10,8 +10,8 @@ module Authorio
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def indieauth_tag
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
tag(:link, rel: 'authorization_endpoint', href: URI.join(root_url, Authorio.authorization_path)) <<
|
|
14
|
+
tag(:link, rel: 'token_endpoint', href: URI.join(root_url, Authorio.token_path))
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Authorio
|
|
2
|
+
class Session < ApplicationRecord
|
|
3
|
+
# Implement a session cookie store based on best security practices
|
|
4
|
+
# See: https://paragonie.com/blog/2015/04/secure-authentication-php-with-long-term-persistence
|
|
5
|
+
belongs_to :authorio_user, class_name: "::Authorio::User"
|
|
6
|
+
|
|
7
|
+
# 1. Protect against having database stolen by only storing token hashes
|
|
8
|
+
attribute :token # This will not be persisted in the DB
|
|
9
|
+
has_secure_token
|
|
10
|
+
|
|
11
|
+
before_create do
|
|
12
|
+
self.expires_at = Time.now + Authorio.configuration.token_expiration
|
|
13
|
+
self.selector = SecureRandom.hex(12)
|
|
14
|
+
self.hashed_token = Digest::SHA256.hexdigest self.token
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# 2. To guard against timing attacks, we lookup tokens based on a separate selector attribute
|
|
18
|
+
# and compare them using a secure time-constant comparison method
|
|
19
|
+
def self.find_by_cookie(cookie)
|
|
20
|
+
_selector, _token = cookie.split(':')
|
|
21
|
+
session = find_by selector: _selector
|
|
22
|
+
raise Authorio::Exceptions::SessionReplayAttack.new(session) unless session.matches_cookie?(cookie)
|
|
23
|
+
session
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def matches_cookie?(cookie)
|
|
27
|
+
_selector, _token = cookie.split(':')
|
|
28
|
+
_hashed_token = Digest::SHA256.hexdigest _token
|
|
29
|
+
!expired? && ActiveSupport::SecurityUtils.secure_compare(_hashed_token, hashed_token)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def expired?
|
|
33
|
+
return expires_at < Time.now
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def as_cookie
|
|
37
|
+
"#{selector}:#{token}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -4,5 +4,13 @@ module Authorio
|
|
|
4
4
|
has_secure_token :auth_token
|
|
5
5
|
|
|
6
6
|
validates_presence_of :scope, :client
|
|
7
|
+
|
|
8
|
+
before_create do
|
|
9
|
+
self.expires_at = Time.now + Authorio.configuration.token_expiration
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def expired?
|
|
13
|
+
return expires_at < Time.now
|
|
14
|
+
end
|
|
7
15
|
end
|
|
8
16
|
end
|
|
@@ -1,37 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<div class="col-md-4">
|
|
17
|
-
</div>
|
|
18
|
-
<div class="col-md-4 auth-panel">
|
|
19
|
-
<h3>Authorio</h3>
|
|
20
|
-
<div class="client-row">
|
|
21
|
-
Authenticating with <span class="client"><%= params[:client_id] %>
|
|
22
|
-
</div>
|
|
23
|
-
<%= form_with(url: "authorize_user", method: :post) do |form| %>
|
|
24
|
-
<%= form.label(:url, "User URL") %>
|
|
25
|
-
<%= form.text_field(:url, value: @user_url, readonly: true) %>
|
|
1
|
+
<%= stylesheet_link_tag "authorio/auth" %>
|
|
2
|
+
<% content_for :title, "Authorio Login" %>
|
|
3
|
+
|
|
4
|
+
<div class="container authorio-auth">
|
|
5
|
+
<div class="row">
|
|
6
|
+
<div class="col-md-4"></div>
|
|
7
|
+
<div class="col-md-4 auth-panel">
|
|
8
|
+
<h3>Authorio</h3>
|
|
9
|
+
<div class="client-row">
|
|
10
|
+
Authenticating with <span class="client"><%= params[:client_id] %>
|
|
11
|
+
</div>
|
|
12
|
+
<%= form_with(model: @user, url: authorize_user_path(@user), method: :post) do |form| %>
|
|
13
|
+
<%= form.label(:url, "User URL") %>
|
|
14
|
+
<%= form.text_field(:url, value: params[:me], readonly: true) %>
|
|
15
|
+
<% unless @user_logged_in_locally %>
|
|
26
16
|
<%= form.label(:password, "Password") %>
|
|
27
17
|
<%= form.password_field(:password, autofocus: true) %>
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
<% if @rememberable %>
|
|
19
|
+
<%= label_tag(:remember_me, class: 'remember') do %>
|
|
20
|
+
<%= form.check_box :remember_me %>
|
|
21
|
+
<span class='r-m'>Remember me for <%= distance_of_time_in_words Authorio.configuration.local_session_lifetime -%></span>
|
|
22
|
+
<% end %>
|
|
30
23
|
<% end %>
|
|
24
|
+
<% end %>
|
|
25
|
+
<div class='auth-btn-row'>
|
|
26
|
+
<%= form.submit("Cancel", class: 'btn btn-default auth-btn') %>
|
|
27
|
+
<%= form.submit("Sign in", class: 'btn btn-success auth-btn') %>
|
|
31
28
|
</div>
|
|
32
|
-
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
29
|
+
<% end %>
|
|
35
30
|
</div>
|
|
36
|
-
|
|
37
|
-
</
|
|
31
|
+
<div class="col-md-4"></div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title><%= yield(:title) %></title>
|
|
5
|
+
<%= csrf_meta_tags %>
|
|
6
|
+
<%= csp_meta_tag %>
|
|
7
|
+
<meta charset="utf-8">
|
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
9
|
+
<link rel="stylesheet"
|
|
10
|
+
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
|
11
|
+
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
|
|
12
|
+
crossorigin="anonymous">
|
|
13
|
+
|
|
14
|
+
<%= stylesheet_link_tag "authorio/application", media: "all" %>
|
|
15
|
+
</head>
|
|
16
|
+
<body data-no-turbolinks="true" data-turbolinks="false">
|
|
17
|
+
|
|
18
|
+
<% flash.each do |key, value| %>
|
|
19
|
+
<div class="alert alert-warning">
|
|
20
|
+
<p><%= value %></p>
|
|
21
|
+
</div>
|
|
22
|
+
<% end %>
|
|
23
|
+
|
|
24
|
+
<%= yield %>
|
|
25
|
+
|
|
26
|
+
</body>
|
|
27
|
+
</html>
|
data/config/routes.rb
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
Authorio::Engine.routes.draw do
|
|
2
2
|
get Authorio.configuration.authorization_endpoint, controller: 'auth', action: 'authorization_interface'
|
|
3
3
|
post Authorio.configuration.authorization_endpoint, controller: 'auth', action: 'send_profile'
|
|
4
|
-
|
|
4
|
+
resources :users do
|
|
5
|
+
post 'authorize', on: :member, to: 'auth#authorize_user'
|
|
6
|
+
end
|
|
5
7
|
get Authorio.configuration.token_endpoint, controller: 'auth', action: 'verify_token'
|
|
6
8
|
post Authorio.configuration.token_endpoint, controller: 'auth', action: 'issue_token'
|
|
7
9
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class CreateAuthorioSessions < ActiveRecord::Migration[6.1]
|
|
2
|
+
def change
|
|
3
|
+
create_table :authorio_sessions do |t|
|
|
4
|
+
t.references :authorio_user, null: false, foreign_key: true
|
|
5
|
+
t.string :selector
|
|
6
|
+
t.string :hashed_token
|
|
7
|
+
t.datetime :expires_at
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
module Authorio
|
|
2
2
|
class Configuration
|
|
3
3
|
|
|
4
|
-
attr_accessor :authorization_endpoint, :token_endpoint, :mount_point
|
|
4
|
+
attr_accessor :authorization_endpoint, :token_endpoint, :mount_point, :token_expiration,
|
|
5
|
+
:local_session_lifetime
|
|
5
6
|
|
|
6
7
|
def initialize
|
|
7
8
|
@authorization_endpoint = "auth"
|
|
8
9
|
@token_endpoint = "token"
|
|
9
10
|
@mount_point = "authorio"
|
|
11
|
+
@token_expiration = 4.weeks
|
|
12
|
+
@local_session_lifetime = nil
|
|
10
13
|
end
|
|
11
14
|
end
|
|
12
15
|
end
|
data/lib/authorio/engine.rb
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
module Authorio
|
|
2
|
-
|
|
2
|
+
class Engine < ::Rails::Engine
|
|
3
3
|
isolate_namespace Authorio
|
|
4
4
|
|
|
5
5
|
initializer "authorio.load_helpers" do |app|
|
|
6
|
-
|
|
6
|
+
Rails.application.reloader.to_prepare do
|
|
7
|
+
ActionView::Base.send :include, Authorio::TagHelper
|
|
8
|
+
end
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
initializer "authorio.assets.precompile" do |app|
|
|
10
12
|
app.config.assets.precompile += %w( authorio/auth.css )
|
|
11
13
|
end
|
|
12
|
-
|
|
13
|
-
end
|
|
14
|
+
end
|
|
14
15
|
end
|
data/lib/authorio/exceptions.rb
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
module Authorio
|
|
2
2
|
module Exceptions
|
|
3
3
|
class InvalidGrant < RuntimeError; end
|
|
4
|
+
class InvalidPassword < RuntimeError; end
|
|
5
|
+
|
|
6
|
+
class SessionReplayAttack < StandardError
|
|
7
|
+
attr_accessor :session
|
|
8
|
+
|
|
9
|
+
def initialize(session)
|
|
10
|
+
@session = session
|
|
11
|
+
end
|
|
12
|
+
end
|
|
4
13
|
end
|
|
5
14
|
end
|
data/lib/authorio/version.rb
CHANGED
|
@@ -12,4 +12,13 @@ Authorio.configure do |config|
|
|
|
12
12
|
|
|
13
13
|
# The path for token requests
|
|
14
14
|
# config.token_endpoint = "token"
|
|
15
|
+
|
|
16
|
+
# How long tokens will last before expiring
|
|
17
|
+
# config.token_expiration = 4.weeks
|
|
18
|
+
|
|
19
|
+
# Enable local session lifetime to keep yourself "logged in" to your own server
|
|
20
|
+
# If set to eg:
|
|
21
|
+
# config.local_session_lifetime = 30.days
|
|
22
|
+
# then you will only have to enter your password every 30 days. Default is off (nil)
|
|
23
|
+
# config.local_session_lifetime = nil
|
|
15
24
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: authorio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Meckler
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-07-
|
|
11
|
+
date: 2021-07-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -34,70 +34,70 @@ dependencies:
|
|
|
34
34
|
name: bcrypt
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
|
-
- - "
|
|
37
|
+
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '3.0'
|
|
40
40
|
type: :runtime
|
|
41
41
|
prerelease: false
|
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
|
-
- - "
|
|
44
|
+
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
46
|
version: '3.0'
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
48
48
|
name: factory_bot_rails
|
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
|
-
- - "
|
|
51
|
+
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
53
|
version: '6.0'
|
|
54
54
|
type: :development
|
|
55
55
|
prerelease: false
|
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
|
58
|
-
- - "
|
|
58
|
+
- - "~>"
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
60
|
version: '6.0'
|
|
61
61
|
- !ruby/object:Gem::Dependency
|
|
62
62
|
name: rspec
|
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
|
64
64
|
requirements:
|
|
65
|
-
- - "
|
|
65
|
+
- - "~>"
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '3.0'
|
|
68
68
|
type: :development
|
|
69
69
|
prerelease: false
|
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
|
71
71
|
requirements:
|
|
72
|
-
- - "
|
|
72
|
+
- - "~>"
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
74
|
version: '3.0'
|
|
75
75
|
- !ruby/object:Gem::Dependency
|
|
76
76
|
name: rspec-rails
|
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
|
79
|
-
- - "
|
|
79
|
+
- - "~>"
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
81
|
version: '5.0'
|
|
82
82
|
type: :development
|
|
83
83
|
prerelease: false
|
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
85
|
requirements:
|
|
86
|
-
- - "
|
|
86
|
+
- - "~>"
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
88
|
version: '5.0'
|
|
89
89
|
- !ruby/object:Gem::Dependency
|
|
90
90
|
name: byebug
|
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
|
92
92
|
requirements:
|
|
93
|
-
- - "
|
|
93
|
+
- - "~>"
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '11.0'
|
|
96
96
|
type: :development
|
|
97
97
|
prerelease: false
|
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
99
99
|
requirements:
|
|
100
|
-
- - "
|
|
100
|
+
- - "~>"
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
102
|
version: '11.0'
|
|
103
103
|
description: Rails engine to add IndieAuth authentication endpoint functionality
|
|
@@ -113,22 +113,22 @@ files:
|
|
|
113
113
|
- app/assets/config/authorio_manifest.js
|
|
114
114
|
- app/assets/stylesheets/authorio/application.css
|
|
115
115
|
- app/assets/stylesheets/authorio/auth.css
|
|
116
|
-
- app/controllers/authorio/application_controller.rb
|
|
117
116
|
- app/controllers/authorio/auth_controller.rb
|
|
118
|
-
- app/
|
|
119
|
-
- app/helpers/authorio/application_helper.rb
|
|
120
|
-
- app/helpers/authorio/test_helper.rb
|
|
117
|
+
- app/helpers/authorio/tag_helper.rb
|
|
121
118
|
- app/jobs/authorio/application_job.rb
|
|
122
119
|
- app/models/authorio/application_record.rb
|
|
123
120
|
- app/models/authorio/request.rb
|
|
121
|
+
- app/models/authorio/session.rb
|
|
124
122
|
- app/models/authorio/token.rb
|
|
125
123
|
- app/models/authorio/user.rb
|
|
126
124
|
- app/views/authorio/auth/authorization_interface.html.erb
|
|
127
|
-
- app/views/layouts/authorio/
|
|
125
|
+
- app/views/layouts/authorio/main.html.erb
|
|
128
126
|
- config/routes.rb
|
|
129
127
|
- db/migrate/20210627230156_create_authorio_users.rb
|
|
130
128
|
- db/migrate/20210627230416_create_authorio_requests.rb
|
|
131
129
|
- db/migrate/20210707230416_create_authorio_tokens.rb
|
|
130
|
+
- db/migrate/20210723161041_add_expiry_to_tokens.rb
|
|
131
|
+
- db/migrate/20210726164625_create_authorio_sessions.rb
|
|
132
132
|
- lib/authorio.rb
|
|
133
133
|
- lib/authorio/configuration.rb
|
|
134
134
|
- lib/authorio/engine.rb
|
|
@@ -138,11 +138,10 @@ files:
|
|
|
138
138
|
- lib/generators/authorio/install/install_generator.rb
|
|
139
139
|
- lib/generators/authorio/install/templates/authorio.rb
|
|
140
140
|
- lib/tasks/authorio_tasks.rake
|
|
141
|
-
homepage:
|
|
141
|
+
homepage:
|
|
142
142
|
licenses:
|
|
143
143
|
- MIT
|
|
144
144
|
metadata:
|
|
145
|
-
homepage_uri: https://rubygems.org/gems/authorio
|
|
146
145
|
source_code_uri: https://github.com/reiterate-app/authorio
|
|
147
146
|
post_install_message:
|
|
148
147
|
rdoc_options: []
|