An OpenIDFilter provides OpenID authentication, listening for upstream OAuth authentication and bypassing if already authorized.
The root URI, “/”, is always bypassed. More URIs can also be bypassed using the :allow option:
use Rack::Session::Pool use OpenIDFilter, :allow => ['/foo', '/bar']
In addition to the :allow option, a block can also be used for more complex decisions:
use Rack::Session::Pool use OpenIDFilter, :allow => ['/foo'] do |url| bar(url) # some method returning true or false end
Responds to the following URIs:
/login /logout /openid_complete
Methods
public class
public instance
Included modules
Public class methods
new
(app, options={}, &bypass_route_callback)
[show source]
# File lib/cloudkit/openid_filter.rb, line 31 31: def initialize(app, options={}, &bypass_route_callback) 32: @app = app 33: @options = options 34: @bypass_route_callback = bypass_route_callback || Proc.new {|url| url == '/'} 35: end
Public instance methods
allow?
(uri)
[show source]
# File lib/cloudkit/openid_filter.rb, line 225 225: def allow?(uri) 226: @bypass_route_callback.call(uri) || 227: @options[:allow] && @options[:allow].include?(uri) 228: end
base_url
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 164 164: def base_url(request) 165: "#{request.scheme}://#{request.env['HTTP_HOST']}/" 166: end
begin_openid_login
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 95 95: def begin_openid_login(request) 96: begin 97: response = openid_consumer(request).begin(request[:openid_url]) 98: rescue => e 99: request.flash[:error] = e 100: return login_redirect(request) 101: end 102: 103: redirect_url = response.redirect_url(base_url(request), full_url(request)) 104: Rack::Response.new([], 302, {'Location' => redirect_url}).finish 105: end
bypass?
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 230 230: def bypass?(request) 231: allow?(request.path_info) || 232: valid_auth_key?(request) || 233: logged_in?(request) 234: end
call
(env)
[show source]
# File lib/cloudkit/openid_filter.rb, line 37 37: def call(env) 38: @@lock.synchronize do 39: @@store = OpenIDStore.new 40: @users = UserStore.new 41: end unless @@store 42: 43: request = Request.new(env) 44: request.announce_auth(CLOUDKIT_OPENID_FILTER_KEY) 45: 46: case request 47: when r(:get, request.login_url); request_login(request) 48: when r(:post, request.login_url); begin_openid_login(request) 49: when r(:get, '/openid_complete'); complete_openid_login(request) 50: when r(:post, request.logout_url); logout(request) 51: else 52: if bypass?(request) 53: @app.call(env) 54: else 55: if request.env[CLOUDKIT_AUTH_CHALLENGE] 56: store_location(request) 57: erb( 58: request, 59: :openid_login, 60: request.env[CLOUDKIT_AUTH_CHALLENGE].merge('Content-Type' => 'text/html'), 61: 401) 62: elsif !request.via.include?(CLOUDKIT_OAUTH_FILTER_KEY) 63: store_location(request) 64: login_redirect(request) 65: else 66: Rack::Response.new('server misconfigured', 500).finish 67: end 68: end 69: end 70: end
complete_openid_login
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 107 107: def complete_openid_login(request) 108: begin 109: idp_response = openid_consumer(request).complete(request.params, full_url(request)) 110: rescue => e 111: request.flash[:error] = e 112: return login_redirect(request) 113: end 114: 115: if idp_response.is_a?(OpenID::Consumer::FailureResponse) 116: request.flash[:error] = idp_response.message 117: return login_redirect(request) 118: end 119: 120: result = @users.get( 121: '/cloudkit_users', 122: # '/cloudkit_login_view', 123: :identity_url => idp_response.endpoint.claimed_id) 124: user_uris = result.parsed_content['uris'] 125: 126: if user_uris.empty? 127: json = JSON.generate(:identity_url => idp_response.endpoint.claimed_id) 128: result = @users.post('/cloudkit_users', :json => json) 129: user_uri = result.parsed_content['uri'] 130: else 131: user_uri = user_uris.first 132: end 133: user_result = @users.resolve_uris([user_uri]).first 134: user = user_result.parsed_content 135: 136: if request.session['user_uri'] = user_uri 137: request.current_user = user_uri 138: user['remember_me_expiration'] = two_weeks_from_now 139: user['remember_me_token'] = Base64.encode64( 140: OpenSSL::Random.random_bytes(32)).gsub(/\W/,'') 141: url = request.session.delete('return_to') 142: response = Rack::Response.new( 143: [], 144: 302, 145: {'Location' => (url || '/'), 'Content-Type' => 'text/html'}) 146: response.set_cookie( 147: 'remember_me', { 148: :value => user['remember_me_token'], 149: :expires => Time.at(user['remember_me_expiration']).utc}) 150: json = JSON.generate(user) 151: @users.put(user_uri, :etag => user_result.etag, :json => json) 152: request.flash[:notice] = 'You have been logged in.' 153: response.finish 154: else 155: request.flash[:error] = 'Could not log on with your OpenID.' 156: login_redirect(request) 157: end 158: end
full_url
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 168 168: def full_url(request) 169: base_url(request) + 'openid_complete' 170: end
logged_in?
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 172 172: def logged_in?(request) 173: logged_in = user_in_session?(request) || valid_remember_me_token?(request) 174: request.current_user = request.session['user_uri'] if logged_in 175: logged_in 176: end
login_redirect
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 160 160: def login_redirect(request) 161: Rack::Response.new([], 302, {'Location' => request.login_url}).finish 162: end
logout
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 72 72: def logout(request) 73: user_uri = request.session.delete('user_uri') 74: result = @users.get(user_uri) 75: user = result.parsed_content 76: user.delete('remember_me_token') 77: user.delete('remember_me_expiration') 78: json = JSON.generate(user) 79: @users.put(user_uri, :etag => result.etag, :json => json) 80: 81: request.env[CLOUDKIT_AUTH_KEY] = nil 82: request.flash['info'] = 'You have been logged out.' 83: response = Rack::Response.new( 84: [], 85: 302, 86: {'Location' => request.login_url, 'Content-Type' => 'text/html'}) 87: response.delete_cookie('remember_me') 88: response.finish 89: end
openid_consumer
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 194 194: def openid_consumer(request) 195: @openid_consumer ||= OpenID::Consumer.new( 196: request.session, OpenIDStore.new) 197: end
request_login
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 91 91: def request_login(request) 92: erb(request, :openid_login) 93: end
root_request?
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 186 186: def root_request?(request) 187: request.path_info == '/' || request.path_info == '/favicon.ico' 188: end
store_location
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 182 182: def store_location(request) 183: request.session['return_to'] = request.url 184: end
two_weeks_from_now
()
[show source]
# File lib/cloudkit/openid_filter.rb, line 221 221: def two_weeks_from_now 222: Time.now.to_i+1209600 223: end
user_in_session?
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 178 178: def user_in_session?(request) 179: request.session['user_uri'] != nil 180: end
valid_auth_key?
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 190 190: def valid_auth_key?(request) 191: request.env[CLOUDKIT_AUTH_KEY] && request.env[CLOUDKIT_AUTH_KEY] != '' 192: end
valid_remember_me_token?
(request)
[show source]
# File lib/cloudkit/openid_filter.rb, line 199 199: def valid_remember_me_token?(request) 200: return false unless token = request.cookies['remember_me'] 201: 202: # result = @users.get('/cloudkit_login_view', :remember_me_token => token) 203: result = @users.get('/cloudkit_users', :remember_me_token => token) 204: return false unless result.status == 200 205: 206: user_uris = result.parsed_content['uris'] 207: return false unless user_uris.try(:size) == 1 208: 209: user_uri = user_uris.first 210: user_result = @users.resolve_uris([user_uri]).first 211: user = user_result.parsed_content 212: return false unless Time.now.to_i < user['remember_me_expiration'] 213: 214: user['remember_me_expiration'] = two_weeks_from_now 215: json = JSON.generate(user) 216: @users.put(user_uri, :etag => user_result.etag, :json => json) 217: request.session['user_uri'] = user_uri 218: true 219: end