userbin 1.1.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +85 -52
- data/lib/userbin.rb +4 -2
- data/lib/userbin/client.rb +55 -11
- data/lib/userbin/errors.rb +1 -1
- data/lib/userbin/models/channel.rb +2 -1
- data/lib/userbin/models/event.rb +6 -0
- data/lib/userbin/models/pairing.rb +7 -0
- data/lib/userbin/models/recovery_code.rb +4 -0
- data/lib/userbin/models/user.rb +5 -0
- data/lib/userbin/request.rb +3 -0
- data/lib/userbin/session_token.rb +4 -0
- data/lib/userbin/version.rb +1 -1
- metadata +5 -3
- data/lib/userbin/models/token.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 744a85b12224637026c348146ce9e1baba43796a
|
4
|
+
data.tar.gz: 52e72314536f2f65636313f0efafd9b7901fb473
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11c9a493bc34d29161da8657a397ea57c3a310a73758b8b2138075bf94ca9bcb52b55fc94c01622e8d90a73b6904d4d2563f68b438911dfd1ab02a2e09f645db
|
7
|
+
data.tar.gz: 6a29b61d8966dbb116f55711000a0e73cdef214cbca9faf6a3e366dcd7303eecca8d9d4def5b9d58e970cd82443c623d5d245886838e016f60d15aa684296c47
|
data/README.md
CHANGED
@@ -27,88 +27,123 @@ Install the gem
|
|
27
27
|
bundle install
|
28
28
|
```
|
29
29
|
|
30
|
-
Load and configure the library with your Userbin API secret in an initializer or similar
|
30
|
+
Load and configure the library with your Userbin API secret in an initializer or similar.
|
31
31
|
|
32
32
|
```ruby
|
33
33
|
require 'userbin'
|
34
34
|
Userbin.api_secret = "YOUR_API_SECRET"
|
35
35
|
```
|
36
36
|
|
37
|
-
##
|
37
|
+
## The basics
|
38
38
|
|
39
|
-
First you'll need to
|
39
|
+
First you'll need to initialize a Userbin client for every incoming HTTP request and preferrably add it to the environment so that it's accessible during the request lifetime.
|
40
40
|
|
41
|
-
|
41
|
+
```ruby
|
42
|
+
env['userbin'] = Userbin::Client.new(request)
|
43
|
+
```
|
42
44
|
|
43
|
-
|
45
|
+
At any time, a call to Userbin might result in an exception, maybe because the user has been logged out. You should catch these errors in one place and take action. Just catch and display all Userbin errors for now.
|
44
46
|
|
45
47
|
```ruby
|
46
48
|
class ApplicationController < ActionController::Base
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# Your controller code here
|
51
|
-
|
52
|
-
private
|
53
|
-
def initialize_userbin
|
54
|
-
# Initialize Userbin and add it to the request environment
|
55
|
-
env['userbin'] = Userbin::Client.new(request)
|
56
|
-
|
57
|
-
if current_user
|
58
|
-
# Optional details for text messages, emails and your dashboard
|
59
|
-
user_properties = {
|
60
|
-
email: current_user.email, # recommended
|
61
|
-
# Add `name`, `username` and `image` for improved experience
|
62
|
-
}
|
63
|
-
|
64
|
-
begin
|
65
|
-
# This checks against Userbin once every 5 minutes under the hood.
|
66
|
-
# The `id` MUST be unique across all your users and roles
|
67
|
-
env['userbin'].authorize!(current_user.id, user_properties)
|
68
|
-
rescue Userbin::Error
|
69
|
-
# Logged out from Userbin; clear your current_user and logout
|
70
|
-
# TODO: implement!
|
71
|
-
end
|
72
|
-
end
|
49
|
+
rescue_from Userbin::Error do |e|
|
50
|
+
redirect_to root_url, alert: e.message
|
73
51
|
end
|
74
52
|
end
|
75
53
|
```
|
76
54
|
|
77
|
-
|
78
|
-
|
79
|
-
### 2. Log out
|
55
|
+
## Tracking user sessions
|
80
56
|
|
81
|
-
|
57
|
+
You should call `login` as soon as the user has logged in to your application. Pass a unique user identifier, and an optional hash of user properties. This starts the Userbin session.
|
82
58
|
|
83
59
|
```ruby
|
84
|
-
def
|
85
|
-
|
60
|
+
def after_login_hook
|
61
|
+
env['userbin'].login(current_user.id, email: current_user.email)
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
And call `logout` just after the user has logged out from your application. This ends the Userbin session.
|
86
66
|
|
87
|
-
|
67
|
+
```ruby
|
68
|
+
def after_logout_hook
|
88
69
|
env['userbin'].logout
|
89
70
|
end
|
90
71
|
```
|
91
72
|
|
92
|
-
|
73
|
+
The session created by login expires typically every 5 minutes and needs to be refreshed with new metadata. This is done by calling authorize. Makes sure that the session hasn't been revoked or locked.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
before_filter do
|
77
|
+
env['userbin'].authorize
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
> **Verify that it works:** Log in to your Ruby application and watch a user appear in the [Userbin dashboard](https://dashboard.userbin.com).
|
93
82
|
|
94
|
-
## Add a link to the user's security settings
|
95
83
|
|
96
|
-
|
84
|
+
## Configuring two-factor authentication
|
85
|
+
|
86
|
+
### Pairing
|
87
|
+
|
88
|
+
#### Google Authenticator
|
89
|
+
|
90
|
+
Create a new Authenticator pairing to get hold of the QR code image to show to the user.
|
97
91
|
|
98
92
|
```ruby
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
93
|
+
authenticator = env['userbin'].pairings.create(type: 'authenticator')
|
94
|
+
|
95
|
+
puts authenticator.qr_url # => "http://..."
|
96
|
+
```
|
97
|
+
|
98
|
+
Catch the code from the user to pair the Authenticator app.
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
authenticator = env['userbin'].pairings.build(id: params[:pairing_id])
|
102
|
+
|
103
|
+
begin
|
104
|
+
authenticator.verify(response: params[:code])
|
105
|
+
rescue
|
106
|
+
flash.notice = 'Wrong code, try again'
|
103
107
|
end
|
104
108
|
```
|
105
109
|
|
106
|
-
|
110
|
+
#### YubiKey
|
107
111
|
|
108
|
-
|
112
|
+
YubiKeys are immediately verified for two-factor authentication.
|
109
113
|
|
114
|
+
```ruby
|
115
|
+
begin
|
116
|
+
env['userbin'].pairings.create(type: 'yubikey', otp: code)
|
117
|
+
rescue
|
118
|
+
flash.notice = 'Wrong code, try again'
|
119
|
+
end
|
120
|
+
```
|
110
121
|
|
111
|
-
|
122
|
+
#### SMS
|
123
|
+
|
124
|
+
Create a new phone number pairing which will send out a verification SMS.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
phone_number = env['userbin'].pairings.create(
|
128
|
+
type: 'phone_number', number: '+1739855455')
|
129
|
+
```
|
130
|
+
|
131
|
+
Catch the code from the user to pair the phone number.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
phone_number = env['userbin'].pairings.build(id: params[:pairing_id])
|
135
|
+
|
136
|
+
begin
|
137
|
+
phone_number.verify(response: params[:code])
|
138
|
+
rescue
|
139
|
+
flash.notice = 'Wrong code, try again'
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
|
144
|
+
### Usage
|
145
|
+
|
146
|
+
#### 1. Protect routes
|
112
147
|
|
113
148
|
If the user has enabled two-factor authentication, `two_factor_authenticate!` will return the second factor that is used to authenticate. If SMS is used, this call will also send out an SMS to the user's registered phone number.
|
114
149
|
|
@@ -138,9 +173,7 @@ class UsersController < ApplicationController
|
|
138
173
|
end
|
139
174
|
```
|
140
175
|
|
141
|
-
|
142
|
-
|
143
|
-
### 2. Show the two-factor authentication form to the user
|
176
|
+
#### 2. Show the two-factor authentication form to the user
|
144
177
|
|
145
178
|
```html
|
146
179
|
<p>
|
@@ -154,7 +187,7 @@ end
|
|
154
187
|
</form>
|
155
188
|
```
|
156
189
|
|
157
|
-
|
190
|
+
#### 3. Verify the code from the user
|
158
191
|
|
159
192
|
The user enters the authentication code in the form and posts it to your handler.
|
160
193
|
|
data/lib/userbin.rb
CHANGED
@@ -23,9 +23,11 @@ end
|
|
23
23
|
|
24
24
|
# These need to be required after setting up Her
|
25
25
|
require 'userbin/models/model'
|
26
|
+
require 'userbin/models/event'
|
26
27
|
require 'userbin/models/challenge'
|
27
28
|
require 'userbin/models/channel'
|
28
|
-
require 'userbin/models/
|
29
|
+
require 'userbin/models/monitoring'
|
30
|
+
require 'userbin/models/pairing'
|
31
|
+
require 'userbin/models/recovery_code'
|
29
32
|
require 'userbin/models/session'
|
30
33
|
require 'userbin/models/user'
|
31
|
-
require 'userbin/models/monitoring'
|
data/lib/userbin/client.rb
CHANGED
@@ -36,23 +36,31 @@ module Userbin
|
|
36
36
|
Userbin::SessionToken.new(token) if token
|
37
37
|
end
|
38
38
|
|
39
|
-
def
|
39
|
+
def identify(user_id)
|
40
40
|
# The user identifier is used in API paths so it needs to be cleaned
|
41
41
|
user_id = URI.encode(user_id.to_s)
|
42
42
|
|
43
43
|
@session_store.user_id = user_id
|
44
|
+
end
|
45
|
+
|
46
|
+
def login(user_id, user_attrs = {})
|
47
|
+
# Clear the session token if any
|
48
|
+
self.session_token = nil
|
44
49
|
|
45
|
-
|
46
|
-
# Create a session, and implicitly a user with user_attrs
|
47
|
-
session = Userbin::Session.post(
|
48
|
-
"users/#{user_id}/sessions", user: user_attrs)
|
50
|
+
identify(user_id)
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
session = Userbin::Session.post(
|
53
|
+
"users/#{@session_store.user_id}/sessions", user: user_attrs)
|
54
|
+
|
55
|
+
# Set the session token for use in all subsequent requests
|
56
|
+
self.session_token = session.token
|
57
|
+
end
|
58
|
+
|
59
|
+
def authorize
|
60
|
+
return unless session_token
|
61
|
+
|
62
|
+
if session_token.expired?
|
63
|
+
Userbin::Monitoring.heartbeat
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
@@ -122,5 +130,41 @@ module Userbin
|
|
122
130
|
session_token.has_challenge?
|
123
131
|
end
|
124
132
|
|
133
|
+
def two_factor_enabled?
|
134
|
+
session_token.mfa_enabled?
|
135
|
+
end
|
136
|
+
|
137
|
+
def two_factor_required?
|
138
|
+
session_token.needs_challenge?
|
139
|
+
end
|
140
|
+
|
141
|
+
def events
|
142
|
+
Userbin::User.new('current').events
|
143
|
+
end
|
144
|
+
|
145
|
+
def sessions
|
146
|
+
Userbin::User.new('current').sessions
|
147
|
+
end
|
148
|
+
|
149
|
+
def pairings
|
150
|
+
Userbin::User.new('current').pairings
|
151
|
+
end
|
152
|
+
|
153
|
+
def channels
|
154
|
+
Userbin::User.new('current').channels
|
155
|
+
end
|
156
|
+
|
157
|
+
def recovery_codes
|
158
|
+
Userbin::User.new('current').recovery_codes
|
159
|
+
end
|
160
|
+
|
161
|
+
def enable_mfa
|
162
|
+
Userbin::User.new('current').enable_mfa
|
163
|
+
end
|
164
|
+
|
165
|
+
def disable_mfa
|
166
|
+
Userbin::User.new('current').disable_mfa
|
167
|
+
end
|
168
|
+
|
125
169
|
end
|
126
170
|
end
|
data/lib/userbin/errors.rb
CHANGED
@@ -6,7 +6,7 @@ class Userbin::ConfigurationError < Userbin::Error; end
|
|
6
6
|
|
7
7
|
class Userbin::ApiError < Userbin::Error; end
|
8
8
|
|
9
|
-
class Userbin::
|
9
|
+
class Userbin::BadRequestError < Userbin::ApiError; end
|
10
10
|
class Userbin::UnauthorizedError < Userbin::ApiError; end
|
11
11
|
class Userbin::ForbiddenError < Userbin::ApiError; end
|
12
12
|
class Userbin::NotFoundError < Userbin::ApiError; end
|
data/lib/userbin/models/user.rb
CHANGED
data/lib/userbin/request.rb
CHANGED
@@ -138,6 +138,9 @@ module Userbin
|
|
138
138
|
when 404
|
139
139
|
raise Userbin::NotFoundError, response[:message]
|
140
140
|
when 419
|
141
|
+
# session token is invalid so clear it
|
142
|
+
RequestStore.store[:userbin].session_token = nil
|
143
|
+
|
141
144
|
raise Userbin::UserUnauthorizedError, response[:message]
|
142
145
|
when 422
|
143
146
|
raise Userbin::InvalidParametersError, response[:message]
|
data/lib/userbin/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: userbin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: her
|
@@ -179,10 +179,12 @@ files:
|
|
179
179
|
- lib/userbin/jwt.rb
|
180
180
|
- lib/userbin/models/challenge.rb
|
181
181
|
- lib/userbin/models/channel.rb
|
182
|
+
- lib/userbin/models/event.rb
|
182
183
|
- lib/userbin/models/model.rb
|
183
184
|
- lib/userbin/models/monitoring.rb
|
185
|
+
- lib/userbin/models/pairing.rb
|
186
|
+
- lib/userbin/models/recovery_code.rb
|
184
187
|
- lib/userbin/models/session.rb
|
185
|
-
- lib/userbin/models/token.rb
|
186
188
|
- lib/userbin/models/user.rb
|
187
189
|
- lib/userbin/request.rb
|
188
190
|
- lib/userbin/session_store.rb
|
data/lib/userbin/models/token.rb
DELETED