authifer 0.0.1rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8d5fca606d9cc2e2a117e9f453aa91bc2dccca57
4
+ data.tar.gz: e98a59759f13e73a33bc75cb7b56a15811a06c69
5
+ SHA512:
6
+ metadata.gz: b11cd52286bbb36c085e9ee5ef3651839f3487e593f64152ec9ad88f080810096642ff518861aaa1e742609e9cae11e89a314a582ab89c924551773b2bc93a50
7
+ data.tar.gz: 3719253f7317fd67c26d084f91146ede71f7a57ac748442434dae7922c2fabf839ffee4933a7e0455464fc04044c10372fe2eebed0bde31bee976dddfde7014e
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Zee Spencer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # Authifer
2
+
3
+ `Trust me Authifer, I'm not half as think as you drunk I am!`
4
+
5
+ One obstacles to chiseling away a monolithic application architecture is
6
+ managing user authentication on several smaller apps.
7
+
8
+ Authifer abstracts authentication into it's own application so you can focus
9
+ your attention on adding useful features for your customers instead of managing
10
+ user identities.
11
+
12
+ ## Usage
13
+
14
+ Gimme a second. I'll figure it out.
15
+
16
+ ## Contributing
17
+
18
+ We love pull requests and issues!
19
+
20
+ ### For enhancements
21
+
22
+ Create an issue or pull request with:
23
+
24
+ 1. A good name
25
+ 2. Tests where applicable
26
+ 3.
27
+
28
+ ### For bug fixes
29
+
30
+ Create an issue with:
31
+
32
+ 1. Reproduction steps
33
+ 2. Stack trace if applicable
34
+ 3. Proposed fix if applicable
data/lib/authifer.rb ADDED
@@ -0,0 +1,21 @@
1
+ require_relative 'authifer/schema'
2
+
3
+ module Authifer
4
+ def self.connect_to_database(database_url)
5
+ require_relative 'authifer/app'
6
+ Authifer::App.set :database, database_url
7
+ require_relative 'authifer/user'
8
+ end
9
+
10
+ def self.views_path=views_path
11
+ @views_path = views_path
12
+ end
13
+
14
+ def self.views_path
15
+ @views_path ||= File.join(base_path, 'views')
16
+ end
17
+
18
+ def self.base_path
19
+ @base_path ||= File.join(File.dirname(File.expand_path(__FILE__)), 'authifer')
20
+ end
21
+ end
@@ -0,0 +1,85 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/activerecord'
3
+ require 'songkick/oauth2/provider'
4
+ require_relative 'authentication_helper'
5
+ require_relative 'renderer'
6
+ require_relative 'oauth_helper'
7
+ require_relative 'data_helper'
8
+ require_relative 'paths'
9
+
10
+ module Authifer
11
+ class App < Sinatra::Base
12
+ register Sinatra::ActiveRecordExtension
13
+
14
+ set :views, Authifer.views_path
15
+ enable :sessions
16
+ extend Authifer::Paths
17
+
18
+ helpers do
19
+ include Authifer::AuthenticationHelper
20
+ include Authifer::OAuthHelper
21
+ include Authifer::DataHelper
22
+ include Authifer::Paths
23
+
24
+
25
+ def display
26
+ @renderer ||= Renderer.new(self)
27
+ end
28
+
29
+ def redirect_url
30
+ @redirect_url ||= params[:redirect_url] || "/"
31
+ end
32
+ end
33
+
34
+ post users_path do
35
+ user = create_user(params[:user])
36
+ if user.persisted?
37
+ login(user)
38
+ redirect redirect_url
39
+ else
40
+ display.register(user)
41
+ end
42
+ end
43
+
44
+ get new_user_path do
45
+ display.register(build_user)
46
+ end
47
+
48
+ post sessions_path do
49
+ user = authenticate_user(params[:user])
50
+ if user.errors.empty?
51
+ login(user)
52
+ redirect redirect_url
53
+ else
54
+ display.login(user)
55
+ end
56
+ end
57
+
58
+ get new_session_path do
59
+ display.login(build_user)
60
+ end
61
+
62
+ [{ method: :get, path: delete_session_path},
63
+ { method: :delete, path: sessions_path }].each do |route|
64
+ __send__(route[:method], route[:path]) do
65
+ logout
66
+ display.login(build_user)
67
+ end
68
+ end
69
+
70
+ before "/oauth/authorize" do
71
+ ensure_logged_in!
72
+ end
73
+
74
+ [:get, :post].each do |method|
75
+ __send__(method, '/oauth/token') { handle_oauth }
76
+ __send__(method, '/oauth/authorize') { handle_oauth }
77
+ end
78
+
79
+ post '/oauth/allow' do
80
+ @auth = Songkick::OAuth2::Provider::Authorization.new(current_user, params)
81
+ @auth.grant_access!
82
+ redirect @auth.redirect_uri, @auth.response_status
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,38 @@
1
+ module Authifer
2
+ module AuthenticationHelper
3
+ def ensure_logged_in!
4
+ unless logged_in?
5
+ @redirect_url = request.fullpath
6
+ halt display.login(build_user)
7
+ end
8
+ end
9
+
10
+ def current_user
11
+ @current_user ||= logged_in? ? find_user(id: session[:user_id]) : build_user
12
+ end
13
+
14
+ def login(user)
15
+ session[:user_id] = user.id
16
+ end
17
+
18
+ def logged_in?
19
+ !session[:user_id].nil?
20
+ end
21
+
22
+ def logout
23
+ session[:user_id] = nil
24
+ end
25
+
26
+ def authenticate_user(user_attributes)
27
+ user = find_user(email: user_attributes[:email])
28
+
29
+ user = build_user if !user
30
+
31
+ if user.password != user_attributes[:password] || user.password.nil?
32
+ user.errors.add(:credentials, "are invalid. We don't have any users with that email/password combination")
33
+ end
34
+
35
+ user
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ module Authifer
2
+ module DataHelper
3
+ def find_user(attributes)
4
+ User.find_by(attributes)
5
+ end
6
+
7
+ def create_user(user_attributes)
8
+ User.create(user_attributes)
9
+ end
10
+
11
+ def build_user(attributes={})
12
+ User.new(attributes)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ module Authifer
2
+ module OAuthHelper
3
+ def resource_owner
4
+ @resource_owner ||= current_user.persisted? ? current_user : :implicit
5
+ end
6
+
7
+ def oauth2
8
+ @oauth2 ||= Songkick::OAuth2::Provider.parse(resource_owner, env)
9
+ end
10
+
11
+ def handle_oauth
12
+ if oauth2.redirect?
13
+ redirect oauth2.redirect_uri, oauth2.response_status
14
+ end
15
+
16
+ headers oauth2.response_headers
17
+ status oauth2.response_status
18
+
19
+ if body = oauth2.response_body
20
+ body
21
+ elsif oauth2.valid?
22
+ erb :authorize, locals: { authorization_request: oauth2 }
23
+ else
24
+ raise "Error Will Robinson"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ module Authifer
2
+ module Paths
3
+ def users_path
4
+ "/users"
5
+ end
6
+
7
+ def new_user_path
8
+ "#{users_path}/new"
9
+ end
10
+
11
+ def sessions_path
12
+ "/sessions"
13
+ end
14
+
15
+ def new_session_path
16
+ "#{sessions_path}/new"
17
+ end
18
+
19
+ def delete_session_path
20
+ "#{sessions_path}/delete"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ module Authifer
2
+ class Renderer
3
+ attr_reader :app
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def login(user)
10
+ if app.logged_in?
11
+ app.redirect app.redirect_url
12
+ else
13
+ app.erb :new_session, locals: { user: user }
14
+ end
15
+ end
16
+
17
+ def register(user)
18
+ if app.logged_in?
19
+ app.redirect app.redirect_url
20
+ else
21
+ app.erb :new_user, locals: { user: user }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ module Authifer
2
+ module Schema
3
+ def self.migrate
4
+ require 'songkick/oauth2/provider'
5
+ Songkick::OAuth2::Model::Schema.migrate
6
+ ActiveRecord::Migrator.up(File.join(Authifer.base_path,'schema'))
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :email, :password_digest
5
+ t.timestamps
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ namespace :authifer do
2
+ namespace :db do
3
+ desc "Migrate up the database"
4
+ task :migrate do
5
+ require_relative 'schema'
6
+ Authifer::Schema.migrate
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ require 'protected_attributes'
2
+ require 'bcrypt'
3
+
4
+ module Authifer
5
+ class User < ActiveRecord::Base
6
+ include Songkick::OAuth2::Model::ResourceOwner
7
+ include Songkick::OAuth2::Model::ClientOwner
8
+
9
+ validates :password, confirmation: true
10
+ validate :password_is_set
11
+ validates :email, uniqueness: true
12
+
13
+ def password=password
14
+ @password = BCrypt::Password.create(password)
15
+ self.password_digest = @password
16
+ end
17
+
18
+ def password
19
+ @password ||= BCrypt::Password.new(password_digest) if password_digest
20
+ end
21
+
22
+ def password_is_set
23
+ if !password || password == ""
24
+ errors.add(:password, "can't be blank")
25
+ end
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,5 @@
1
+ <% if model.errors.has_key? field %>
2
+ <% model.errors.messages[field].each do |m|%>
3
+ <p class="error"><%= field.to_s.capitalize %> <%= m %></p>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1 @@
1
+ <input type="hidden" name="redirect_url" value="<%=redirect_url%>" />
@@ -0,0 +1,9 @@
1
+ <h2>You're about to grant access to <%= authorization_request.client.name %></h2>
2
+ <form method="POST" action="/oauth/allow">
3
+ <% authorization_request.params.each do |key, value| %>
4
+ <input type="hidden" name="<%= key %>" value="<%= value %>">
5
+ <% end %>
6
+ <button>It's cool. I dig it</button>
7
+ </form>
8
+ <a href="http://calmingmanatee.com/">No thanks. I'd rather see a picture of a
9
+ manatee</a>
@@ -0,0 +1,5 @@
1
+ <!DOCTYPE html>
2
+ <body>
3
+ <%= yield %>
4
+ </body>
5
+ </html>
@@ -0,0 +1,13 @@
1
+ <div id="login_form">
2
+ <form method="POST" action="<%= sessions_path %>">
3
+ <%= erb :_error, locals: { model: user, field: :credentials } %>
4
+ <label>Email: <input type="email" name="user[email]" value="<%=user.email%>"></label>
5
+ <%= erb :_error, locals: { model: user, field: :email } %>
6
+
7
+ <label>Password: <input type="password" name="user[password]"></label>
8
+ <%= erb :_error, locals: { model: user, field: :password } %>
9
+
10
+ <%= erb :_redirect_url_fields %>
11
+ <button>Log in</button>
12
+ </form>
13
+ </div>
@@ -0,0 +1,15 @@
1
+ <div id="registration_form">
2
+ <form method="POST" action="<%= users_path %>">
3
+ <label>Email: <input type="email" name="user[email]" value="<%=user.email%>"></label>
4
+ <%= erb :_error, locals: { model: user, field: :email } %>
5
+
6
+ <label>Password: <input type="password" name="user[password]"></label>
7
+ <%= erb :_error, locals: { model: user, field: :password } %>
8
+
9
+ <label>Confirm Password: <input type="password" name="user[password_confirmation]"></label>
10
+ <%= erb :_error, locals: { model: user, field: :password_confirmation } %>
11
+
12
+ <%= erb :_redirect_url_fields %>
13
+ <button>Register</button>
14
+ </form>
15
+ </div>
metadata ADDED
@@ -0,0 +1,230 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: authifer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1rc1
5
+ platform: ruby
6
+ authors:
7
+ - Zee Spencer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sinatra
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sinatra-activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: songkick-oauth2-provider
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.10'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bcrypt-ruby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: protected_attributes
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: oauth2
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: capybara
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: minitest
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: minitest-test
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: dotenv
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: pg
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ description: Run your own Authentication provider!
182
+ email: zee@zeespencer.com
183
+ executables: []
184
+ extensions: []
185
+ extra_rdoc_files: []
186
+ files:
187
+ - lib/authifer/views/_error.erb
188
+ - lib/authifer/views/_redirect_url_fields.erb
189
+ - lib/authifer/views/authorize.erb
190
+ - lib/authifer/views/layout.erb
191
+ - lib/authifer/views/new_session.erb
192
+ - lib/authifer/views/new_user.erb
193
+ - lib/authifer/app.rb
194
+ - lib/authifer/authentication_helper.rb
195
+ - lib/authifer/data_helper.rb
196
+ - lib/authifer/oauth_helper.rb
197
+ - lib/authifer/paths.rb
198
+ - lib/authifer/renderer.rb
199
+ - lib/authifer/schema/20131029055507_create_users.rb
200
+ - lib/authifer/schema.rb
201
+ - lib/authifer/tasks.rb
202
+ - lib/authifer/user.rb
203
+ - lib/authifer.rb
204
+ - README.md
205
+ - LICENSE
206
+ homepage: https://github.com/makeheadspace/authifer
207
+ licenses:
208
+ - MIT
209
+ metadata: {}
210
+ post_install_message:
211
+ rdoc_options: []
212
+ require_paths:
213
+ - lib
214
+ required_ruby_version: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - '>='
217
+ - !ruby/object:Gem::Version
218
+ version: '0'
219
+ required_rubygems_version: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - '>'
222
+ - !ruby/object:Gem::Version
223
+ version: 1.3.1
224
+ requirements: []
225
+ rubyforge_project:
226
+ rubygems_version: 2.0.3
227
+ signing_key:
228
+ specification_version: 4
229
+ summary: Run your own Authentication provider!
230
+ test_files: []