entrance 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/sinatra-app/app/models.rb +1 -1
- data/examples/sinatra-app/app/views/login.erb +1 -1
- data/examples/sinatra-omniauth/Gemfile +11 -0
- data/examples/sinatra-omniauth/README.md +13 -0
- data/examples/sinatra-omniauth/app/models.rb +33 -0
- data/examples/sinatra-omniauth/app/routes.rb +45 -0
- data/examples/sinatra-omniauth/app/views/layout.erb +26 -0
- data/examples/sinatra-omniauth/app/views/login.erb +5 -0
- data/examples/sinatra-omniauth/app/views/welcome.erb +3 -0
- data/examples/sinatra-omniauth/config.ru +5 -0
- data/lib/entrance/addons/omniauth.rb +27 -17
- data/lib/entrance/controller.rb +12 -1
- data/lib/entrance/fields.rb +26 -26
- data/lib/entrance/model.rb +15 -6
- data/lib/entrance/version.rb +1 -1
- metadata +10 -2
@@ -4,7 +4,7 @@ require 'mongo_mapper'
|
|
4
4
|
require 'entrance'
|
5
5
|
|
6
6
|
MongoMapper.connection = Mongo::Connection.new('localhost')
|
7
|
-
MongoMapper.database = 'entrance-example'
|
7
|
+
MongoMapper.database = 'entrance-omniauth-example'
|
8
8
|
|
9
9
|
Entrance.configure do |config|
|
10
10
|
config.remember_for = 1.month
|
@@ -0,0 +1,13 @@
|
|
1
|
+
## Example Sinatra App with Entrance
|
2
|
+
|
3
|
+
A quick example that shows how to use Entrance with a Sinatra modular app. Requires MongoDB.
|
4
|
+
|
5
|
+
To run:
|
6
|
+
|
7
|
+
git clone https://github.com/tomas/entrance
|
8
|
+
cd entrance/examples/sinatra-app
|
9
|
+
bundle install
|
10
|
+
# (start mongo, eg 'mongodb --dbpath=/var/lib/mongodb')
|
11
|
+
bundle exec puma
|
12
|
+
|
13
|
+
And ready-o. Then point your browser to localhost:9292 and sign up, then sign in using your credentials.
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'mongo_mapper'
|
4
|
+
require 'entrance'
|
5
|
+
|
6
|
+
MongoMapper.connection = Mongo::Connection.new('localhost')
|
7
|
+
MongoMapper.database = 'entrance-example'
|
8
|
+
|
9
|
+
Entrance.configure do |config|
|
10
|
+
config.remember_for = 1.month
|
11
|
+
config.cookie_secure = false # for testing
|
12
|
+
end
|
13
|
+
|
14
|
+
class User
|
15
|
+
include MongoMapper::Document
|
16
|
+
include Entrance::Model
|
17
|
+
|
18
|
+
key :state, :default => 'active'
|
19
|
+
|
20
|
+
key :name
|
21
|
+
key :auth_provider, String
|
22
|
+
key :auth_uid, String
|
23
|
+
|
24
|
+
key :remember_token
|
25
|
+
key :remember_token_expires_at, Time
|
26
|
+
|
27
|
+
provides_entrance :local => false
|
28
|
+
|
29
|
+
def active?
|
30
|
+
state.to_sym == :active
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
%w(./app/models sinatra/base sinatra/flash).each { |lib| require lib }
|
2
|
+
|
3
|
+
require 'entrance/addons/omniauth'
|
4
|
+
require 'omniauth-twitter'
|
5
|
+
|
6
|
+
module Example
|
7
|
+
|
8
|
+
class Routes < Sinatra::Base
|
9
|
+
|
10
|
+
register Sinatra::Flash
|
11
|
+
register Entrance::OmniAuth
|
12
|
+
|
13
|
+
set :sessions, :secret => 'veryverysecretkey'
|
14
|
+
set :views, File.expand_path(File.dirname(__FILE__)) + '/views'
|
15
|
+
|
16
|
+
set :auth_test, true # only true for testing
|
17
|
+
set :auth_remember, true # enables 'remember me' for omniauth logins
|
18
|
+
set :auth_providers, {
|
19
|
+
:twitter => {
|
20
|
+
:key => 'foobar',
|
21
|
+
:secret => 'xoxoxoxox'
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
before do
|
26
|
+
login_required :except => ['/login']
|
27
|
+
end
|
28
|
+
|
29
|
+
get '/' do
|
30
|
+
erb :welcome
|
31
|
+
end
|
32
|
+
|
33
|
+
get '/login' do
|
34
|
+
erb :login
|
35
|
+
end
|
36
|
+
|
37
|
+
get '/logout' do
|
38
|
+
logout!
|
39
|
+
flash[:notice] = 'Logged out! See you soon.'
|
40
|
+
redirect to('/login')
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html xml:lang="en" lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8" />
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
6
|
+
|
7
|
+
<title>Example Entrance App</title>
|
8
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<body>
|
12
|
+
|
13
|
+
<div id="container" class="clearfix">
|
14
|
+
|
15
|
+
<% [:error, :notice, :success].each do |msg| %>
|
16
|
+
<% if flash && flash[msg] %>
|
17
|
+
<%= "<div class='alert alert-#{msg}'>#{flash[msg]}</div>" %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<%= yield %>
|
22
|
+
|
23
|
+
</div>
|
24
|
+
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -5,13 +5,14 @@ require 'omniauth'
|
|
5
5
|
|
6
6
|
require 'sinatra/base'
|
7
7
|
require 'omniauth-twitter'
|
8
|
-
require 'entrance/omniauth'
|
8
|
+
require 'entrance/addons/omniauth'
|
9
9
|
|
10
10
|
class Hello < Sinatra::Base
|
11
11
|
register Entrance::OmniAuth
|
12
12
|
|
13
|
-
set :auth_test, false
|
14
|
-
set :
|
13
|
+
set :auth_test, false # only true for testing
|
14
|
+
set :auth_remember, true # enables 'remember me' for omniauth logins
|
15
|
+
set :auth_providers, {
|
15
16
|
:twitter => {
|
16
17
|
:key => 'foobar'
|
17
18
|
}
|
@@ -26,13 +27,17 @@ module Entrance
|
|
26
27
|
|
27
28
|
class << self
|
28
29
|
|
30
|
+
def providers
|
31
|
+
@providers ||= []
|
32
|
+
end
|
33
|
+
|
29
34
|
def registered(app)
|
30
35
|
|
31
36
|
::Entrance.model.class_eval do
|
32
37
|
|
33
38
|
def via_omniauth?
|
34
|
-
send(::Entrance.
|
35
|
-
&& send(::Entrance.
|
39
|
+
send(::Entrance.fields.auth_provider).present? \
|
40
|
+
&& send(::Entrance.fields.auth_uid).present?
|
36
41
|
end
|
37
42
|
|
38
43
|
def password_required?
|
@@ -53,6 +58,9 @@ module Entrance
|
|
53
58
|
# puts "Initializing #{name} provider: #{options.inspect}"
|
54
59
|
opts = options || {}
|
55
60
|
provider(name, opts[:key], opts[:secret], opts[:extra] || {})
|
61
|
+
|
62
|
+
app.allow_paths.push("/auth/#{name}/callback")
|
63
|
+
::Entrance::OmniAuth.providers.push(name.to_sym)
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
@@ -66,20 +74,22 @@ module Entrance
|
|
66
74
|
user = ::Entrance::OmniAuth.auth_or_create(auth) or return return_401
|
67
75
|
|
68
76
|
if ::Entrance::OmniAuth.valid_user?(user)
|
69
|
-
login!(user)
|
77
|
+
login!(user, app.settings.auth_remember)
|
70
78
|
flash[:success] = 'Welcome back!' if respond_to?(:flash)
|
71
79
|
redirect_to_stored_or(to('/'))
|
72
80
|
else
|
73
|
-
redirect_with(
|
81
|
+
redirect_with(Entrance.config.access_denied_redirect_to, :error, 'Unable to authenticate. Please try again.')
|
74
82
|
end
|
75
83
|
end
|
76
84
|
|
77
85
|
end # get, post
|
78
86
|
|
79
87
|
app.get '/auth/failure' do
|
80
|
-
redirect_with(
|
88
|
+
redirect_with(Entrance.config.access_denied_redirect_to, :error, params[:message])
|
81
89
|
end
|
82
90
|
|
91
|
+
app.allow_paths.push("/auth/failure")
|
92
|
+
|
83
93
|
end # registered
|
84
94
|
|
85
95
|
def logger
|
@@ -87,7 +97,7 @@ module Entrance
|
|
87
97
|
end
|
88
98
|
|
89
99
|
def log(str)
|
90
|
-
logger.info(str)
|
100
|
+
logger.info(str) rescue nil
|
91
101
|
end
|
92
102
|
|
93
103
|
def valid_user?(user)
|
@@ -99,25 +109,25 @@ module Entrance
|
|
99
109
|
|
100
110
|
def can_authenticate_with?(service)
|
101
111
|
return true if ::OmniAuth.config.test_mode and service.to_sym == :default
|
102
|
-
|
112
|
+
::Entrance::OmniAuth.providers.include?(service.to_sym)
|
103
113
|
end
|
104
114
|
|
105
115
|
def find_user_with_username(username)
|
106
116
|
query = {}
|
107
|
-
query[::Entrance.
|
117
|
+
query[::Entrance.fields.username] = username # .to_s.downcase.strip
|
108
118
|
::Entrance.model.where(query).first
|
109
119
|
end
|
110
120
|
|
111
121
|
def find_user_with_provider_and_uid(provider, uid)
|
112
122
|
query = {}
|
113
|
-
query[::Entrance.
|
114
|
-
query[::Entrance.
|
123
|
+
query[::Entrance.fields.auth_provider] = provider
|
124
|
+
query[::Entrance.fields.auth_uid] = uid
|
115
125
|
::Entrance.model.where(query).first
|
116
126
|
end
|
117
127
|
|
118
128
|
def set_auth_credentials(user, provider, uid)
|
119
|
-
user[::Entrance.
|
120
|
-
user[::Entrance.
|
129
|
+
user[::Entrance.fields.auth_provider] = provider
|
130
|
+
user[::Entrance.fields.auth_uid] = uid
|
121
131
|
end
|
122
132
|
|
123
133
|
def store_auth_credentials(user, provider, uid)
|
@@ -127,8 +137,8 @@ module Entrance
|
|
127
137
|
|
128
138
|
def create_user(name, email, provider, uid)
|
129
139
|
data = {}
|
130
|
-
data[::Entrance.
|
131
|
-
data[::Entrance.
|
140
|
+
data[::Entrance.fields.name] = name
|
141
|
+
data[::Entrance.fields.username] = email
|
132
142
|
user = ::Entrance.model.new(data)
|
133
143
|
set_auth_credentials(user, provider, uid)
|
134
144
|
|
data/lib/entrance/controller.rb
CHANGED
@@ -4,8 +4,18 @@ module Entrance
|
|
4
4
|
|
5
5
|
REMEMBER_ME_TOKEN = 'auth_token'.freeze
|
6
6
|
|
7
|
+
module ClassMethods
|
8
|
+
|
9
|
+
# lets us do app.skip_paths.push('/specific/path/we/want/unprotected')
|
10
|
+
def allow_paths
|
11
|
+
@allow_paths ||= []
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
7
16
|
def self.included(base)
|
8
17
|
base.send(:helper_method, :current_user, :logged_in?, :logged_out?) if base.respond_to?(:helper_method)
|
18
|
+
base.extend(ClassMethods)
|
9
19
|
end
|
10
20
|
|
11
21
|
def authenticate_and_login(username, password, remember_me = false)
|
@@ -29,7 +39,8 @@ module Entrance
|
|
29
39
|
end
|
30
40
|
|
31
41
|
def login_required(opts = {})
|
32
|
-
|
42
|
+
allowed = (opts[:except] || []) + self.class.allow_paths
|
43
|
+
return if allowed.any? and allowed.include?(request.path_info)
|
33
44
|
logged_in? || access_denied
|
34
45
|
end
|
35
46
|
|
data/lib/entrance/fields.rb
CHANGED
@@ -26,43 +26,43 @@ module Entrance
|
|
26
26
|
@auth_uid = 'auth_uid'
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
|
29
|
+
def validate_field(attr)
|
30
|
+
field = send(attr)
|
31
|
+
unless fields.include?(field.to_sym)
|
32
|
+
raise "Couldn't find '#{field}' in the #{Entrance.model.name} model."
|
33
|
+
end
|
34
|
+
end
|
31
35
|
|
32
|
-
|
36
|
+
def validate_option(what)
|
37
|
+
if field = send("#{what}_token")
|
38
|
+
until_field = send("#{what}_until")
|
33
39
|
|
34
|
-
%w(username password).each do |attr|
|
35
|
-
field = send(attr)
|
36
40
|
unless fields.include?(field.to_sym)
|
37
|
-
raise "
|
41
|
+
raise "No #{field} field found. \
|
42
|
+
Set the fields.#{what}_token option to nil to disable the #{what} option."
|
38
43
|
end
|
39
|
-
end
|
40
|
-
|
41
|
-
%w(remember reset).each do |what|
|
42
|
-
if field = send("#{what}_token")
|
43
|
-
until_field = send("#{what}_until")
|
44
|
-
|
45
|
-
unless fields.include?(field.to_sym)
|
46
|
-
raise "No #{field} field found. \
|
47
|
-
Set the fields.#{what} option to nil to disable the #{what} option."
|
48
|
-
end
|
49
44
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
else
|
55
|
-
puts "Disabling expiration timestamp for the #{what} option. This is a VERY bad idea."
|
45
|
+
if until_field
|
46
|
+
unless fields.include?(until_field.to_sym)
|
47
|
+
raise "Couldn't find a #{until_field} field. Cannot continue."
|
56
48
|
end
|
49
|
+
else
|
50
|
+
puts "Disabling expiration timestamp for the #{what} option. This is a VERY bad idea."
|
51
|
+
end
|
57
52
|
|
58
|
-
|
53
|
+
Entrance.config.can?(what, true)
|
59
54
|
|
60
|
-
|
61
|
-
|
62
|
-
end
|
55
|
+
mod = what.to_sym == :remember ? Entrance::Model::RememberMethods : Entrance::Model::ResetMethods
|
56
|
+
Entrance.model.send(:include, mod)
|
63
57
|
end
|
64
58
|
end
|
65
59
|
|
60
|
+
protected
|
61
|
+
|
62
|
+
def fields
|
63
|
+
@fields ||= get_model_fields
|
64
|
+
end
|
65
|
+
|
66
66
|
def get_model_fields
|
67
67
|
model = Entrance.model
|
68
68
|
if model.respond_to?(:columns) # ActiveRecord::Base
|
data/lib/entrance/model.rb
CHANGED
@@ -7,8 +7,9 @@ module Entrance
|
|
7
7
|
|
8
8
|
module ClassMethods
|
9
9
|
|
10
|
-
def provides_entrance(&block)
|
10
|
+
def provides_entrance(options = {}, &block)
|
11
11
|
Entrance.config.model = self.name
|
12
|
+
local = options.delete(:local) != false
|
12
13
|
|
13
14
|
# if the target model class does not have a Model.where() method,
|
14
15
|
# then login_by_session wont work, nor the ClassMethods below.
|
@@ -19,12 +20,20 @@ module Entrance
|
|
19
20
|
|
20
21
|
fields = Entrance.fields
|
21
22
|
yield fields if block_given?
|
22
|
-
fields.validate!
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
# username and remember token are used both for local and remote (omniauth)
|
25
|
+
fields.validate_field(:username)
|
26
|
+
fields.validate_option(:remember)
|
27
|
+
|
28
|
+
if local # allows password & reset
|
29
|
+
fields.validate_field(:password)
|
30
|
+
fields.validate_option(:reset)
|
31
|
+
|
32
|
+
if self.respond_to?(:validates)
|
33
|
+
validates :password, :presence => true, :length => 6..32, :if => :password_required?
|
34
|
+
validates :password, :confirmation => true, :if => :password_required?
|
35
|
+
validates :password_confirmation, :presence => true, :if => :password_required?
|
36
|
+
end
|
28
37
|
end
|
29
38
|
end
|
30
39
|
|
data/lib/entrance/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: entrance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-03-
|
12
|
+
date: 2015-03-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bcrypt
|
@@ -111,6 +111,14 @@ files:
|
|
111
111
|
- examples/sinatra-app/app/views/signup.erb
|
112
112
|
- examples/sinatra-app/app/views/welcome.erb
|
113
113
|
- examples/sinatra-app/config.ru
|
114
|
+
- examples/sinatra-omniauth/Gemfile
|
115
|
+
- examples/sinatra-omniauth/README.md
|
116
|
+
- examples/sinatra-omniauth/app/models.rb
|
117
|
+
- examples/sinatra-omniauth/app/routes.rb
|
118
|
+
- examples/sinatra-omniauth/app/views/layout.erb
|
119
|
+
- examples/sinatra-omniauth/app/views/login.erb
|
120
|
+
- examples/sinatra-omniauth/app/views/welcome.erb
|
121
|
+
- examples/sinatra-omniauth/config.ru
|
114
122
|
- lib/entrance.rb
|
115
123
|
- lib/entrance/addons/omniauth.rb
|
116
124
|
- lib/entrance/addons/sinatra.rb
|