4
4
require 'warden'
5
5
require 'roda'
6
6
require 'omniauth'
7
- require 'omniauth-twitter'
8
- require 'omniauth-facebook'
9
7
10
8
class Roda
11
-
9
+
12
10
module RodaPlugins
13
11
14
12
module Auth
15
-
13
+
16
14
def self . load_dependencies ( app , *args , &block )
17
15
app . plugin :drop_body
18
16
app . plugin :environments
19
17
Warden ::Strategies . add ( :token , Strategies ::Token )
20
18
Warden ::Strategies . add ( :password , Strategies ::Password )
21
19
Warden ::Strategies . add ( :basic , Strategies ::Basic )
22
20
end
23
-
21
+
24
22
def self . configure ( app , *args )
25
23
options = args . last . is_a? ( Hash ) ? args . pop : { }
26
- user_class = options . delete ( :user_class ) || ::User
27
24
type = args [ 0 ] || :basic
28
- redirect = options . delete ( :redirect ) || 'login'
29
- cookie = options . delete ( :cookie ) || { secret : 'secr3t' }
25
+ user_class = options . delete ( :user_class ) || :: User
26
+ redirect = options . delete ( :redirect ) || '/login'
30
27
case type
31
28
when :basic
32
29
strategies = [ :basic ]
33
30
when :form
34
31
strategies = [ :password ]
35
- app . use Rack ::Session ::Cookie , cookie
36
- Warden ::Manager . serialize_into_session do |user |
37
- user . id
38
- end
39
- Warden ::Manager . serialize_from_session do |id |
40
- user_class . find_by_id ( id )
41
- end
42
- app . use OmniAuth ::Builder do
43
- provider :developer unless app . production?
44
- provider :twitter , ENV [ 'TWITTER_KEY' ] , ENV [ 'TWITTER_SECRET' ]
45
- provider :facebook , ENV [ 'FACEBOOK_KEY' ] , ENV [ 'FACEBOOK_SECRET' ]
46
- end
47
32
when :token
48
- app . use Rack ::Session ::Cookie , cookie
49
33
strategies = [ :token , :password ]
50
34
end
51
35
app . use Warden ::Manager do |config |
@@ -58,18 +42,12 @@ def self.configure(app, *args)
58
42
:action => redirect
59
43
)
60
44
end
61
- if providers = options . delete ( :omniauth )
62
- app . use OmniAuth ::Builder do
63
- provider :developer unless app . production?
64
- providers . each do |name |
65
- key = ENV [ "API_#{ name . to_s . upcase } _KEY" ]
66
- secret = ENV [ "API_#{ name . to_s . upcase } _SECRET" ]
67
- provider name , key , secret
68
- end
69
- end
45
+ if strategies . include? :password
46
+ setup_cookie ( app , user_class , options )
47
+ setup_omniauth ( app , options )
70
48
end
71
49
end
72
-
50
+
73
51
def self . fail ( type )
74
52
auth_fail = case type
75
53
when :basic
@@ -81,157 +59,192 @@ def self.fail(type)
81
59
end
82
60
-> ( env ) { auth_fail . call ( env ) }
83
61
end
84
-
62
+
63
+ def self . setup_cookie ( app , user_class , options )
64
+ cookie = options . delete ( :cookie ) || { secret :'secr3t' }
65
+ app . use Rack ::Session ::Cookie , cookie
66
+ Warden ::Manager . serialize_into_session do |user |
67
+ user . id
68
+ end
69
+ Warden ::Manager . serialize_from_session do |id |
70
+ user_class . find_by_id ( id )
71
+ end
72
+ app . plugin :csrf , raise : true , skip_if : lambda { |request |
73
+ request . env . key? 'HTTP_AUTHORIZATION'
74
+ }
75
+ end
76
+
77
+ def self . setup_omniauth ( app , options )
78
+ if providers = options . delete ( :omniauth )
79
+ app . use OmniAuth ::Builder do
80
+ provider :developer unless app . production?
81
+ providers . each do |name |
82
+ key = ENV [ "API_#{ name . to_s . upcase } _KEY" ]
83
+ secret = ENV [ "API_#{ name . to_s . upcase } _SECRET" ]
84
+ provider name , key , secret
85
+ end
86
+ end
87
+ end
88
+ end
89
+
85
90
module InstanceMethods
86
-
91
+
87
92
def authenticate!
93
+ return current_user if current_user
88
94
user = warden . authenticate!
89
- warden . set_user ( user )
95
+ set_user ( user )
96
+ user
90
97
end
91
98
99
+ def unauthenticate!
100
+ #lifted from devise
101
+ warden . raw_session . inspect # Without this inspect here. The session does not clear.
102
+ warden . logout ( scope )
103
+ warden . clear_strategies_cache! ( scope : scope )
104
+ end
105
+
92
106
def current_user
93
107
warden . user
94
108
end
95
-
96
- def sign_in &block
97
- user = warden . authenticate!
109
+
110
+ def set_user ( user )
98
111
warden . set_user ( user )
112
+ end
113
+
114
+ def sign_in &block
115
+ user = authenticate!
99
116
request . is ( &block ) if block
100
117
user
101
118
end
102
-
119
+
103
120
def sign_out &block
104
- #lifted from devise
105
- warden . raw_session . inspect # Without this inspect here. The session does not clear.
106
- warden . logout ( scope )
107
- warden . clear_strategies_cache! ( scope : scope )
108
-
121
+ unauthenticate!
109
122
request . response . status = 204
110
123
request . is ( &block ) if block
111
124
end
112
-
125
+
113
126
private
114
-
127
+
115
128
def scope
116
129
:user
117
130
end
118
-
131
+
119
132
def warden
120
133
request . env [ 'warden' ]
121
134
end
122
-
135
+
123
136
def session_path
124
137
roda_class . opts [ :session_path ] . to_s
125
138
end
126
-
139
+
127
140
end
128
-
141
+
129
142
end
130
-
143
+
131
144
module Strategies
132
-
145
+
133
146
class Base < Warden ::Strategies ::Base
134
-
147
+
135
148
def success! ( user )
136
149
user . authentic! if user . respond_to? ( :authentic! )
137
150
super
138
151
end
139
-
152
+
140
153
def authenticate!
141
154
user = warden . config [ :user_class ] . authentic? ( credentials )
142
155
user . nil? ? fail! ( "Could not log in" ) : success! ( user )
143
156
end
144
-
157
+
145
158
private
146
-
159
+
147
160
def warden
148
161
@env [ 'warden' ]
149
162
end
150
-
163
+
151
164
def credentials_from_basic
152
165
header = authorization_header
153
166
return unless header && header =~ /\A Basic (.*)/m
154
167
username , password = Base64 . decode64 ( $1) . split ( /:/ , 2 )
155
168
return unless username and password
156
169
{ 'username' => username , 'password' => password }
157
170
end
158
-
171
+
159
172
def credentials_from_form
160
173
request . media_type == "application/x-www-form-urlencoded" && params
161
174
end
162
-
175
+
163
176
def credentials_from_body
164
177
if request . body
165
178
body = request . body . read
166
179
!body . empty? && JSON . parse ( body )
167
180
end
168
181
end
169
-
182
+
170
183
def token_from_auth_header
171
184
return unless header = authorization_header
172
185
match = header =~ /\A Auth (.*)/m
173
186
match && { 'token' => $1 }
174
187
end
175
-
188
+
176
189
def authorization_header
177
190
@env [ 'HTTP_AUTHORIZATION' ] || @env [ 'X-HTTP_AUTHORIZATION' ] || @env [ 'X_HTTP_AUTHORIZATION' ] || @env [ 'REDIRECT_X_HTTP_AUTHORIZATION' ]
178
191
end
179
-
192
+
180
193
end
181
194
182
-
195
+
183
196
class Password < Base
184
-
197
+
185
198
def valid?
186
199
credentials [ 'username' ] && credentials [ 'password' ]
187
200
end
188
-
201
+
189
202
private
190
-
203
+
191
204
def credentials
192
205
@credentials ||= credentials_from_form || credentials_from_body || { }
193
206
end
194
-
207
+
195
208
end
196
-
209
+
197
210
class Basic < Password
198
-
211
+
199
212
def valid?
200
213
credentials [ 'username' ] && credentials [ 'password' ]
201
214
end
202
-
215
+
203
216
# def result
204
217
# :redirect
205
218
# end
206
-
219
+
207
220
private
208
-
221
+
209
222
def credentials
210
223
@credentials ||= credentials_from_basic || { }
211
224
end
212
-
225
+
213
226
end
214
227
215
-
228
+
216
229
class Token < Base
217
-
230
+
218
231
def valid?
219
232
credentials [ 'token' ]
220
233
end
221
-
234
+
222
235
private
223
-
236
+
224
237
def credentials
225
238
@credentials ||= token_from_auth_header || { }
226
239
end
227
-
240
+
228
241
end
229
-
242
+
230
243
end
231
-
244
+
232
245
register_plugin ( :auth , Auth )
233
-
246
+
234
247
end
235
-
248
+
236
249
237
250
end
0 commit comments