entrance 0.4.2 → 0.4.3

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.
@@ -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
@@ -18,5 +18,5 @@
18
18
  <input class="right btn btn-primary" tabindex="3" type="submit" value="Log in" />
19
19
 
20
20
  </form>
21
-
21
+
22
22
  <p>Don't have an account? <a href="<%= url('/signup') %>">Sign up</a>.</p>
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rack', '1.5.2'
4
+ gem 'sinatra'
5
+ gem 'sinatra-flash'
6
+ gem 'puma'
7
+ gem 'mongo_mapper'
8
+ gem 'bson_ext'
9
+ gem 'omniauth'
10
+ gem 'omniauth-twitter'
11
+ gem 'entrance', :path => './../../'
@@ -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>
@@ -0,0 +1,5 @@
1
+ <h2>Log in</h2>
2
+
3
+ <% Entrance::OmniAuth.providers.each do |name| %>
4
+ <a href="/auth/<%= name %>">Login with <%= name %></a>
5
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <h1>Welcome <%= current_user.name %>!</h1>
2
+
3
+ <p>You're now logged in. Now it's time to <a href="<%= url('/logout') %>">log out</a>.</p>
@@ -0,0 +1,5 @@
1
+ require './app/routes'
2
+
3
+ map '/' do
4
+ run Example::Routes
5
+ end
@@ -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 # only true for testing
14
- set :auth_providers {
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.config.auth_provider_attr).present? \
35
- && send(::Entrance.config.auth_uid_attr).present?
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('/', :error, 'Unable to authenticate. Please try again.')
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('/', :error, params[:message])
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
- settings.auth_providers.keys.map(&:to_sym).include?(service.to_sym)
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.config.username_attr] = username # .to_s.downcase.strip
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.config.auth_provider_attr] = provider
114
- query[::Entrance.config.auth_uid_attr] = uid
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.config.auth_provider_attr] = provider
120
- user[::Entrance.config.auth_uid_attr] = uid
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.config.name_attr] = name
131
- data[::Entrance.config.username_attr] = email
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
 
@@ -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
- return if opts[:except] and opts[:except].include?(request.path_info)
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
 
@@ -26,43 +26,43 @@ module Entrance
26
26
  @auth_uid = 'auth_uid'
27
27
  end
28
28
 
29
- def validate!
30
- raise "Invalid model: #{Entrance.config.model}!" unless Kernel.const_defined?(Entrance.config.model)
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
- fields = get_model_fields
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 "Couldn't find '#{field}' in the #{Entrance.model.name} model."
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
- if until_field
51
- unless fields.include?(until_field.to_sym)
52
- raise "Couldn't find a #{until_field} field. Cannot continue."
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
- Entrance.config.can?(what, true)
53
+ Entrance.config.can?(what, true)
59
54
 
60
- mod = what.to_sym == :remember ? Entrance::Model::RememberMethods : Entrance::Model::ResetMethods
61
- Entrance.model.send(:include, mod)
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
@@ -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
- if self.respond_to?(:validates)
25
- validates :password, :presence => true, :length => 6..32, :if => :password_required?
26
- validates :password, :confirmation => true, :if => :password_required?
27
- validates :password_confirmation, :presence => true, :if => :password_required?
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
 
@@ -1,7 +1,7 @@
1
1
  module Entrance
2
2
  MAJOR = 0
3
3
  MINOR = 4
4
- PATCH = 2
4
+ PATCH = 3
5
5
 
6
6
  VERSION = [MAJOR, MINOR, PATCH].join('.')
7
7
  end
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.2
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-13 00:00:00.000000000 Z
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