chowder 0.2

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.
Files changed (3) hide show
  1. data/lib/chowder.rb +176 -0
  2. data/lib/sinatra/chowder.rb +28 -0
  3. metadata +76 -0
data/lib/chowder.rb ADDED
@@ -0,0 +1,176 @@
1
+ require 'sinatra/base'
2
+ require 'ostruct'
3
+ require 'openid'
4
+ require 'openid/store/filesystem'
5
+
6
+ module Chowder
7
+ class Base < Sinatra::Base
8
+ disable :raise_errors
9
+
10
+ LOGIN_VIEW = <<-HTML
11
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
12
+ <html lang='en-us' xmlns='http://www.w3.org/1999/xhtml'>
13
+ <head><title>Log In</title></head>
14
+ <body>
15
+ <form action="/login" method="post">
16
+ <div id="basic_login_field">
17
+ <label for="login">Login: </label>
18
+ <input id="login" type="text" name="login" /><br />
19
+ </div>
20
+ <div id="basic_password_field">
21
+ <label for="password">Password: </label>
22
+ <input id="password" type="password" name="password" /><br />
23
+ </div>
24
+ <div id="basic_login_button">
25
+ <input type="submit" value="Login" />
26
+ </div>
27
+ </form>
28
+ <p>OpenID:</p>
29
+ <form action="/openid/initiate" method="post">
30
+ <div id="openid_login_field">
31
+ <label for="openid_identifier">URL: </label>
32
+ <input id="openid_identifier" type="text" name="openid_identifier" /><br />
33
+ </div>
34
+ <div id="openid_login_button">
35
+ <input type="submit" value="Login" />
36
+ </div>
37
+ </form>
38
+ </body></html>
39
+ HTML
40
+
41
+ SIGNUP_VIEW = <<-HTML
42
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
43
+ <html lang='en-us' xmlns='http://www.w3.org/1999/xhtml'>
44
+ <head><title>Sign Up</title></head>
45
+ <body>
46
+ __ERRORS__
47
+ <form action="/signup" method="post">
48
+ <div id="basic_login_field">
49
+ <label for="login">Login: </label>
50
+ <input id="login" type="text" name="login" /><br />
51
+ </div>
52
+ <div id="basic_password_field">
53
+ <label for="password">Password: </label>
54
+ <input id="password" type="password" name="password" /><br />
55
+ </div>
56
+ <div id="basic_signup_button">
57
+ <input type="submit" value="Sign Up" />
58
+ </div>
59
+ </form>
60
+ </body></html>
61
+ HTML
62
+
63
+ def self.new(app=nil, args={}, &block)
64
+ builder = Rack::Builder.new
65
+ builder.use Rack::Session::Cookie, :secret => args[:secret]
66
+ builder.run super
67
+ builder.to_app
68
+ end
69
+
70
+ def initialize(app=nil, args={}, &block)
71
+ @signup_callback = args[:signup]
72
+ @login_callback = args[:login] || block
73
+ super(app)
74
+ end
75
+
76
+ def authorize(user)
77
+ session[:current_user] = user
78
+ end
79
+
80
+ def return_or_redirect_to(path)
81
+ redirect(session[:return_to] || path)
82
+ end
83
+
84
+ def render_custom_template(type)
85
+ views_dir = self.options.views || "./views"
86
+ template = Dir[File.join(views_dir, "#{type}.*")].first
87
+ if template
88
+ engine = File.extname(template)[1..-1]
89
+ send(engine, type)
90
+ end
91
+ end
92
+
93
+ get '/login' do
94
+ render_custom_template(:login) || LOGIN_VIEW
95
+ end
96
+
97
+ get '/logout' do
98
+ session[:current_user] = nil
99
+ redirect '/'
100
+ end
101
+ end
102
+
103
+ class Basic < Base
104
+ post '/login' do
105
+ login, password = params['login'], params['password']
106
+ if authorize @login_callback.call(login, password)
107
+ return_or_redirect_to '/'
108
+ else
109
+ redirect '/login'
110
+ end
111
+ end
112
+
113
+ get '/signup' do
114
+ if @signup_callback
115
+ render_custom_template(:signup) || signup_view_with_errors([])
116
+ else
117
+ throw :pass
118
+ end
119
+ end
120
+
121
+ post '/signup' do
122
+ throw :pass unless @signup_callback
123
+
124
+ # results is either [true, <userid>] or [false, <errors>]
125
+ successful_signup, *extras = @signup_callback.call(params)
126
+ if successful_signup
127
+ authorize extras[0]
128
+ return_or_redirect_to '/'
129
+ else
130
+ @errors = extras
131
+ render_custom_template(:signup) || signup_view_with_errors(extras)
132
+ SIGNUP_VIEW.gsub(
133
+ /__ERRORS__/,
134
+ @errors.map { |e| "<p class=\"error\">#{e}</p>" }.join("\n")
135
+ )
136
+ end
137
+ end
138
+
139
+ private
140
+ def signup_view_with_errors(errors)
141
+ SIGNUP_VIEW.gsub(
142
+ /__ERRORS__/,
143
+ errors.map { |e| "<p class=\"error\">#{e}</p>" }.join("\n")
144
+ )
145
+ end
146
+ end
147
+
148
+ class OpenID < Base
149
+ def host
150
+ host = env['HTTP_HOST'] || "#{env['SERVER_NAME']}:#{env['SERVER_PORT']}"
151
+ "http://#{host}"
152
+ end
153
+
154
+ def setup_consumer
155
+ store = ::OpenID::Store::Filesystem.new('.openid')
156
+ osession = session[:openid] ||= {}
157
+ @consumer = ::OpenID::Consumer.new(osession, store)
158
+ end
159
+
160
+ post '/openid/initiate' do
161
+ setup_consumer
162
+ url = @consumer.begin(params['openid_identifier']).redirect_url(host, host + '/openid/authenticate')
163
+ redirect url
164
+ end
165
+
166
+ get '/openid/authenticate' do
167
+ setup_consumer
168
+ res = @consumer.complete(request.params, host + '/openid/authenticate')
169
+ user = @login_callback.call(res.identity_url)
170
+ if res.is_a?(::OpenID::Consumer::SuccessResponse) && authorize(user)
171
+ return_or_redirect_to '/'
172
+ end
173
+ redirect '/login'
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,28 @@
1
+ require 'sinatra/base'
2
+
3
+ module Sinatra
4
+ module Chowder
5
+ def current_user
6
+ session[:current_user]
7
+ end
8
+
9
+ def authorized?
10
+ session[:current_user]
11
+ end
12
+
13
+ def login
14
+ session[:redirect_to] = request.path_info
15
+ redirect '/login'
16
+ end
17
+
18
+ def logout
19
+ session[:current_user] = nil
20
+ end
21
+
22
+ def require_user
23
+ login unless authorized?
24
+ end
25
+ end
26
+
27
+ helpers Chowder
28
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chowder
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.2"
5
+ platform: ruby
6
+ authors:
7
+ - Harry Vangberg
8
+ - Sam Merritt
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-03-11 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: sinatra
18
+ type: :runtime
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 0.9.1
25
+ version:
26
+ - !ruby/object:Gem::Dependency
27
+ name: ruby-openid
28
+ type: :runtime
29
+ version_requirement:
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ version:
36
+ description:
37
+ email: harry@vangberg.name
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - lib/chowder.rb
46
+ - lib/sinatra/chowder.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/ichverstehe/chowder
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.3.5
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: rack middleware providing session based authentication
75
+ test_files: []
76
+