browserid-auth-rails 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Greg Look
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,194 @@
1
+ Modified fork of [https://github.com/mvxcvi/browserid-rails](https://github.com/mvxcvi/browserid-rails) to be compatible with Devise.
2
+
3
+ # BrowserID::Rails
4
+
5
+ This gem provides a lightweight single-sign-on authentication structure to a
6
+ Rails application based on
7
+ [Mozilla's Persona service](https://login.persona.org/about). Persona
8
+ authenticates clients uniquely by their email address using the BrowserID
9
+ protocol, without exposing clients' browsing behaviors to the identity provider.
10
+ This also frees the application from needing to securely handle and store user
11
+ credentials.
12
+
13
+ ## Overview
14
+
15
+ BrowserID affords a very easy SSO experience for clients. A simplified version
16
+ of the authentication flow goes like this:
17
+
18
+ 1. The user clicks a login link on the site.
19
+ 2. A pop-up window directs the user to authenticate with their identity
20
+ provider. This will either be their email provider or Mozilla's fall-back
21
+ Persona service.
22
+ 3. If the authentication is successful, the browser acquires a certificate
23
+ proving that the client owns the email address in question. This only needs
24
+ to be done once for an email address across any number of domains; after
25
+ that the user can just click a button to use that address to authenticate.
26
+ 4. The browser then uses the certificate to sign an authentication assertion
27
+ for the site (given by the `audience` parameter).
28
+ 5. The browser POSTs the signed assertion to a session creation URL for
29
+ verification. If the assertion is valid, the authenticated email is stored
30
+ in the client's session and the page is reloaded.
31
+
32
+ At this point, the `browserid_email` method will return the stored email
33
+ address, and `browserid_current_user` will look up the authenticated user model.
34
+ See below for more detailed documentation of the available controller and helper
35
+ methods.
36
+
37
+ Logging out is also straightforward:
38
+
39
+ 1. The (authenticated) user clicks a logout link on the site.
40
+ 2. The browser clears its stored assertion for the site and POSTs a
41
+ request to the server to clear its login state.
42
+ 3. The server removes the authenticated email stored in the client's session
43
+ and reloads the page.
44
+
45
+ ## Installation
46
+
47
+ Add this line to your application's Gemfile:
48
+
49
+ gem 'browserid-rails'
50
+
51
+ And then execute:
52
+
53
+ $ bundle
54
+
55
+ Or install it yourself as:
56
+
57
+ $ gem install browserid-rails
58
+
59
+ ## Usage
60
+
61
+ To use this gem once it is installed, it must be integrated into your Rails
62
+ application. The following sections cover the gem configuration, controller
63
+ integration, and view integration.
64
+
65
+ ### Configuration
66
+
67
+ There are several configuration options available. There are a number of default
68
+ assumptions about the application, which may be overridden as needed.
69
+ Configuration settings are properties of `config.browserid`.
70
+
71
+ * `user_model` - The name of the ActiveModel class for application users.
72
+ The default is `"User"`.
73
+ * `email_field` - The attribute of the user model which contains the user's
74
+ email. The default is `:email`.
75
+ * `session_variable` - The location the authenticated email is stored in the
76
+ client's session. The default is `:browserid_email`.
77
+ * `verifier` - The type of verifier to use to authenticate client BrowserID
78
+ assertions. The default is `:persona`, which sends the request to Mozilla's
79
+ Persona verification service. In the future, `:local` will enable local
80
+ verification code. Alternately, this configuration option may be set to any
81
+ object which responds to `#verify(assertion, audience)` with the verified
82
+ email and identity provider on success and raises an error on failure.
83
+ * `audience` - The BrowserID audience to authenticate to. This should consist
84
+ of a URI string containing the scheme (protocol), authority, and port of the
85
+ service (e.g., `"https://app.example.com:443"`). By default, the audience is
86
+ not hardcoded and the properties of the request object are used to construct
87
+ it dynamically. This gives greater flexibility while developing, but is also
88
+ a minor security risk. In production, this should be configured to a fixed
89
+ value.
90
+
91
+ Additionally, there are two sub-structures `login` and `logout` for configuring
92
+ the associated paths and default link text. They have the following properties:
93
+
94
+ * `text` - The default text to give login and logout links.
95
+ * `path` - The target to give links and the path to `POST` authentication
96
+ requests to. Defaults to `"/login"` and `"/logout"` respectively.
97
+
98
+ So, if you wanted the application to use 'signin' and 'signout' instead, you
99
+ could do the following:
100
+
101
+ config.browserid.login.text = "Sign-in"
102
+ config.browserid.login.path = '/signin'
103
+ config.browserid.logout.text = "Sign-out"
104
+ config.browserid.logout.path = '/signout'
105
+
106
+ ### Controller Integration
107
+
108
+ The `BrowserID::Rails::Base` module makes several controller methods available
109
+ to interact with the authentication system. To access information, use one of:
110
+
111
+ * `browserid_email` - Returns the BrowserID-authenticated email address, if any.
112
+ * `browserid_current_user` - Retrieves the model for the currently authenticated
113
+ user, if there is an authenticated email and a matching user exists.
114
+ * `browserid_authenticated?` - Returns true if there is a current user.
115
+
116
+ These methods are also available in views as helpers.
117
+
118
+ To control authentication, the app should have a `SessionsController` which
119
+ connects the in-browser authentication code to the server. The gem provides
120
+ these methods:
121
+
122
+ * `login_browserid` - Sets the given string as the authenticated email.
123
+ * `logout_browserid` - Clears the current authenticated email.
124
+ * `verify_browserid` - Uses the configured verifier to confirm a BrowserID
125
+ assertion is correct for the service audience.
126
+ * `respond_to_browserid` - Wraps `verify_browserid` in logging and error
127
+ handling logic and generates controller responses to a `POST` assertion.
128
+
129
+ Implementing the required methods for `SessionsController` is straightforward:
130
+
131
+ # POST /login
132
+ def create
133
+ respond_to_browserid
134
+ end
135
+
136
+ # POST /logout
137
+ def destroy
138
+ logout_browserid
139
+ head :ok
140
+ end
141
+
142
+ ### Layout Integration
143
+
144
+ The BrowserID javascript library needs to be loaded on your application pages.
145
+ There are two steps to accomplish this:
146
+
147
+ First, the coffeescript asset file needs to be loaded. In the
148
+ `app/assets/javascripts/application.js` manifest, add the following line:
149
+
150
+ //= require browserid
151
+
152
+ Second, the scripts need to be setup in your pages' `<head>` section. The
153
+ `setup_browserid` helper method takes care of this for you and gives a couple
154
+ of ways to control its behavior:
155
+
156
+ <!-- Perform basic BrowserID setup in the head section -->
157
+ <%= setup_browserid %>
158
+
159
+ <!-- Setup BrowserID with alert debugging -->
160
+ <%= setup_browserid debug: true %>
161
+
162
+ <!-- Setup BrowserID with a custom handler -->
163
+ <%= setup_browserid do %>
164
+ browserid.onLogin = function (data, status, xhr) {
165
+ // ...
166
+ }
167
+ <% end %>
168
+
169
+ Once that's accomplished, the app is ready to use BrowserID for authentication.
170
+ To add login and logout links to the site, use the `login_link` and
171
+ `logout_link` helpers. These accept an optional link text as a parameter:
172
+
173
+ <%= logout_link %>
174
+
175
+ <%= login_link "Login with Persona" %>
176
+
177
+ The coffeescript asset adds on-click handlers to the links which trigger the
178
+ Persona code to request new assertions or destroy existing ones.
179
+
180
+ ## Contributing
181
+
182
+ 1. Fork it
183
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
184
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
185
+ 4. Push to the branch (`git push origin my-new-feature`)
186
+ 5. Create new Pull Request
187
+
188
+ ## Future Work
189
+
190
+ * In the future, it would be nice to have a generator to create routes and
191
+ session controller skeletons. This would simplify setup and integration with
192
+ new apps quite a bit.
193
+ * Another to-do item is to incorporate the Persona branding assets and add more
194
+ helpers for generating login buttons.
@@ -0,0 +1,84 @@
1
+ # BrowserID javascript functions
2
+
3
+ @browserid = browserid =
4
+
5
+ ### PROPERTIES ###
6
+
7
+ # Public: Path used to verify browserID authentication assertions. Assertions
8
+ # are POSTed to this path.
9
+ loginPath: '/login'
10
+
11
+ # Public: Path used to unset persisted authentication state when logging out.
12
+ # This should clear the currently-logged-in user email.
13
+ logoutPath: '/logout'
14
+
15
+ # Internal: Debugging toggle - if true, the results of logins will be alert
16
+ # dialogs instead of page refreshes. This is useful to set if the application
17
+ # starts going into a refresh loop.
18
+ debug: false
19
+
20
+
21
+
22
+ ### HANDLERS ###
23
+
24
+ # Public: This method is called when a user successfully authenticates. By
25
+ # default, it reloads the current page.
26
+ onLogin: (data, status, xhr) ->
27
+ if @debug
28
+ alert("Login: #{status}\n#{data}")
29
+ else
30
+ window.location.reload()
31
+
32
+ # Public: This method is called when a user fails to authenticate.
33
+ onLoginError: (xhr, status, err) ->
34
+ alert("Login: #{status} #{err}\n#{xhr.responseText}")
35
+
36
+ # Public: This method is called when a user clears their authentication. By
37
+ # default, it reloads the current page.
38
+ onLogout: (data, status, xhr) ->
39
+ if @debug
40
+ alert("Logout: #{status}\n#{data}")
41
+ else
42
+ window.location.reload()
43
+
44
+ # Public: This method is called when a user fails to clear their
45
+ # authentication.
46
+ onLogoutError: (xhr, status, err) ->
47
+ alert("Logout: #{status} #{err}\n#{xhr.responseText}")
48
+
49
+
50
+ ### INITIALIZATION ###
51
+
52
+ # Public: Watches the authentication state and takes action when the user
53
+ # logs in or logs out. This method MUST be called on every page of the
54
+ # application.
55
+ setup: (currentUser = null) ->
56
+ navigator.id.watch
57
+ loggedInUser: currentUser
58
+ onlogin: (assertion) =>
59
+ $.ajax
60
+ type: 'POST'
61
+ url: @loginPath
62
+ data: { assertion: assertion }
63
+ success: (data, status, xhr) => @onLogin(data, status, xhr)
64
+ error: (xhr, status, err) => @onLoginError(xhr, status, err)
65
+ onlogout: =>
66
+ $.ajax
67
+ type: 'POST'
68
+ url: @logoutPath
69
+ success: (data, status, xhr) => @onLogout(data, status, xhr)
70
+ error: (xhr, status, err) => @onLogoutError(xhr, status, err)
71
+
72
+
73
+
74
+ ### Behavior Binding ###
75
+
76
+ jQuery ->
77
+ $('.browserid_login').click ->
78
+ navigator.id.request()
79
+ false
80
+
81
+ jQuery ->
82
+ $('.browserid_logout').click ->
83
+ navigator.id.logout()
84
+ false
@@ -0,0 +1,12 @@
1
+ <script src="https://login.persona.org/include.js"></script>
2
+ <script type="text/javascript">
3
+ <% if options[:login_path] %>browserid.loginPath = "<%= options[:login_path] %>";<% end %>
4
+ <% if options[:logout_path] %>browserid.logoutPath = "<%= options[:logout_path] %>";<% end %>
5
+ <% if options[:debug] %>browserid.debug = true;<% end %>
6
+ <%= yield :browserid_setup %>
7
+ <% if browserid_email %>
8
+ browserid.setup("<%= browserid_email %>");
9
+ <% else %>
10
+ browserid.setup();
11
+ <% end %>
12
+ </script>
@@ -0,0 +1 @@
1
+ require 'browserid-rails'
@@ -0,0 +1,56 @@
1
+ require 'browserid/rails/base'
2
+ require 'browserid/rails/helpers'
3
+ require 'browserid/rails/version'
4
+
5
+ module BrowserID
6
+ module Rails
7
+ # This class defines a Rails engine which extends the base controller with
8
+ # the library methods. The presence of this engine also causes assets to
9
+ # be included when the gem is added as a dependency.
10
+ class Engine < ::Rails::Engine
11
+ # Initialize the engine configuration.
12
+ config.before_configuration do
13
+ BrowserIDConfig = Struct.new :user_model, :email_field, :session_variable, :verifier, :audience, :login, :logout
14
+ BrowserIDLinkConfig = Struct.new :text, :path
15
+
16
+ config.browserid = BrowserIDConfig.new.tap do |cfg|
17
+ cfg.user_model = 'User'
18
+ cfg.email_field = :email
19
+ cfg.session_variable = :browserid_email
20
+ cfg.verifier = :persona
21
+ # audience should only be set in production
22
+
23
+ cfg.login = BrowserIDLinkConfig.new.tap do |link|
24
+ link.text = "Login"
25
+ link.path = '/login'
26
+ end
27
+
28
+ cfg.logout = BrowserIDLinkConfig.new.tap do |link|
29
+ link.text = "Logout"
30
+ link.path = '/logout'
31
+ end
32
+ end
33
+ end
34
+
35
+ # Mix in the controller and view helper methods.
36
+ config.before_initialize do
37
+ ActionController::Base.send :include, BrowserID::Rails::Base
38
+ ActionView::Base.send :include, BrowserID::Rails::Helpers
39
+ end
40
+
41
+ # Create the assertion verifier.
42
+ config.after_initialize do
43
+ cfg = config.browserid
44
+
45
+ # Replace type symbol with constructed verifier.
46
+ if cfg.verifier == :persona
47
+ cfg.verifier = BrowserID::Verifier::Persona.new
48
+ elsif cfg.verifier == :local
49
+ raise "Local BrowserID verification is not supported yet" # TODO
50
+ elsif !cfg.verifier.respond_to?(:verify)
51
+ raise "Unknown BrowserID verifier type #{cfg.verifier}"
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,131 @@
1
+ require 'browserid/verifier/persona'
2
+
3
+ module BrowserID
4
+ module Rails
5
+ # Public: Base module for inclusion into a controller. This module includes
6
+ # methods for dealing with BrowserID user authentication.
7
+ module Base
8
+
9
+ ##### INTERNAL METHODS #####
10
+
11
+ # Internal: Modifies the controller this module is included in to provide
12
+ # authentication-related helper methods
13
+ #
14
+ # base - The Class this module is being included in.
15
+ def self.included(base)
16
+ base.send :helper_method, :browserid_config, :browserid_email, :browserid_current_user, :browserid_authenticated?
17
+ end
18
+
19
+ # Internal: Gets the application configuration for this gem.
20
+ #
21
+ # Returns the app config structure.
22
+ def browserid_config
23
+ ::Rails.application.config.browserid
24
+ end
25
+
26
+
27
+
28
+ ##### HELPER METHODS #####
29
+
30
+ # Public: Gets the email address of the currently-authenticated user.
31
+ #
32
+ # Returns the authenticated email address String.
33
+ def browserid_email
34
+ session[browserid_config.session_variable]
35
+ end
36
+
37
+ # Public: Retrieves the user for the authenticated email address. This
38
+ # method uses the `browserid.user_model` and `browserid.email_field`
39
+ # config settings, which default to `User` and `email`.
40
+ #
41
+ # Returns the current authenticated user, or nil if no user exists.
42
+ def browserid_current_user
43
+ if browserid_email.nil?
44
+ nil
45
+ elsif @browserid_current_user
46
+ @browserid_current_user
47
+ else
48
+ config = browserid_config
49
+ user_model = config.user_model.constantize
50
+ find_method = "find_by_#{config.email_field}".intern
51
+
52
+ @browserid_current_user = user_model.send find_method, browserid_email
53
+ end
54
+ end
55
+
56
+ # Public: Determines whether the current client is authenticated as a
57
+ # registered User.
58
+ #
59
+ # Returns true if the client is authenticated and registered.
60
+ def browserid_authenticated?
61
+ !browserid_current_user.nil?
62
+ end
63
+
64
+
65
+
66
+ ##### AUTHENTICATION METHODS #####
67
+
68
+ # Public: Sets the given email address as the currently-authenticated user.
69
+ # The address is saved in the client's session.
70
+ #
71
+ # email - The String email address to consider authenticated.
72
+ def login_browserid(email)
73
+ session[browserid_config.session_variable] = email
74
+ end
75
+
76
+ # Public: Clears the saved email address for the currently-authenticated
77
+ # user. It is important to note that this does not remove the BrowserID
78
+ # assertion in the client's browser.
79
+ def logout_browserid
80
+ session[browserid_config.session_variable] = nil
81
+ end
82
+
83
+ # Public: Uses the configured verifier to check that a provided assertion
84
+ # is correct for the site audience.
85
+ #
86
+ # Returns the verified email, identity issuer, and audience on success.
87
+ # Raises an error with a failure message if the client was not
88
+ # successfully authenticated.
89
+ #
90
+ # Examples
91
+ #
92
+ # verify_browserid(assertion)
93
+ # # => "user@example.com", "persona.mozilla.com", "https://app.example.com:443"
94
+ #
95
+ def verify_browserid(assertion)
96
+ audience = browserid_config.audience
97
+ audience ||= "%s%s:%d" % [request.protocol, request.host, request.port]
98
+ browserid_config.verifier.verify(assertion, audience)
99
+ end
100
+
101
+ # Public: Handles a POST-ed BrowserID assertion, responding appropriately
102
+ # to the request. If successful, this logs-in the authenticated email and
103
+ # returns an OK status. If unsuccessful, it returns FORBIDDEN and an
104
+ # error message in the response body.
105
+ #
106
+ # Returns nothing.
107
+ #
108
+ # Examples
109
+ #
110
+ # # POST /login
111
+ # def create
112
+ # respond_to_browserid
113
+ # end
114
+ #
115
+ def respond_to_browserid
116
+ if params[:assertion].blank?
117
+ head :bad_request
118
+ else
119
+ email, issuer, audience = verify_browserid params[:assertion]
120
+ logger.info "Verified BrowserID assertion for #{email} issued by #{issuer} on #{audience}"
121
+ login_browserid email
122
+ head :ok
123
+ end
124
+ rescue StandardError => e
125
+ # TODO: distinguish between process failures and invalid assertions
126
+ logger.warn "Failed to verify BrowserID assertion: #{e.message}"
127
+ render status: :forbidden, text: e.message
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,67 @@
1
+ module BrowserID
2
+ module Rails
3
+ # Public: Rails view helpers for use with BrowserID code.
4
+ module Helpers
5
+ # Public: Renders a layout partial which initializes the BrowserID
6
+ # system. This should be called in the head of the application layout.
7
+ #
8
+ # options - Hash used to adjust the browserid asset setup (default: {}).
9
+ # :login_path - String giving the path to POST assertions to
10
+ # for verification. Defaults to the configured
11
+ # `browserid.login.path`.
12
+ # :logout_path - String giving the path to POST logout
13
+ # notifications to. Defaults to the configured
14
+ # `browserid.logout.path`.
15
+ # :debug - Boolean determining whether the browserid
16
+ # javascript will refresh the page or show an
17
+ # alert dialog.
18
+ # block - An optional block which can be used to provide additional
19
+ # content to be rendered inside the browserid setup script tag.
20
+ #
21
+ # Examples
22
+ #
23
+ # <!-- Perform basic BrowserID setup in the head section -->
24
+ # <%= setup_browserid %>
25
+ #
26
+ # <!-- Setup BrowserID with alert debugging -->
27
+ # <%= setup_browserid debug: true %>
28
+ #
29
+ # <!-- Setup BrowserID with a custom handler -->
30
+ # <%= setup_browserid do %>
31
+ # browserid.onLogin = function (data, status, xhr) {
32
+ # // ...
33
+ # }
34
+ # <% end %>
35
+ #
36
+ def setup_browserid(options={}, &block)
37
+ defaults = { login_path: browserid_config.login.path, logout_path: browserid_config.logout.path }
38
+ content_for :browserid_setup, capture(&block) if block_given?
39
+ render 'shared/browserid', options: defaults.merge(options)
40
+ end
41
+
42
+ # Public: Renders a login link which will request a new authentication
43
+ # assertion from the BrowserID javascript code. The default link text is
44
+ # configurable with `config.browserid.login.text`. The link target is
45
+ # similarly configurable with `config.browserid.login.path`.
46
+ #
47
+ # text - Optional String to use as link text (default: configured value).
48
+ def login_link(text=nil)
49
+ text ||= browserid_config.login.text
50
+ target = browserid_config.login.path || '#'
51
+ link_to text, target, class: :browserid_login
52
+ end
53
+
54
+ # Public: Renders a logout link which will clear the current BrowserID
55
+ # authentication status. The default link text is configurable with
56
+ # `config.browserid.logout.text`. The link target is similarly
57
+ # configurable with `config.browserid.logout.path`.
58
+ #
59
+ # text - Optional String to use as link text (default: configured value).
60
+ def logout_link(text=nil)
61
+ text ||= browserid_config.logout.text
62
+ target = browserid_config.logout.path || '#'
63
+ link_to text, target, class: :browserid_logout
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,5 @@
1
+ module BrowserID
2
+ module Rails
3
+ VERSION = "0.5.3"
4
+ end
5
+ end
@@ -0,0 +1,85 @@
1
+ require 'json'
2
+ require 'net/https'
3
+
4
+ module BrowserID
5
+ module Verifier
6
+ # Public: This class sends the assertion to Mozilla's Persona server for
7
+ # verification.
8
+ class Persona
9
+ attr_accessor :server, :path
10
+
11
+ # Public: String defining the endpoint of the server to perform Persona
12
+ # verifications against.
13
+ VERIFICATION_SERVER = 'verifier.login.persona.org'
14
+
15
+ # Public: String defining the normal path to POST assertion verifications
16
+ # to.
17
+ VERIFICATION_PATH = '/verify'
18
+
19
+ # Public: Constructs a new Persona verifier.
20
+ #
21
+ # server - Domain String of the server to send assertions to for
22
+ # verifications (default: VERIFICATION_SERVER).
23
+ # path - Path String to POST to on the server (default:
24
+ # VERIFICATION_PATH).
25
+ #
26
+ def initialize(server=VERIFICATION_SERVER, path=VERIFICATION_PATH)
27
+ @server = server
28
+ @path = path
29
+ end
30
+
31
+ # Public: Verifies a Persona assertion for a given audience.
32
+ #
33
+ # assertion - Persona authentication assertion.
34
+ # audience - Audience String to verify assertion against. This should be
35
+ # the URI of the service with scheme, authority, and port.
36
+ #
37
+ # Returns the authenticated email address String and the issuing domain
38
+ # if the assertion is valid.
39
+ # Raises an exception with a failure message if the client was not
40
+ # successfully authenticated.
41
+ #
42
+ # Examples
43
+ #
44
+ # verify(assertion, "https://app.example.com:443")
45
+ # # => "user@example.com", "persona.mozilla.com"
46
+ #
47
+ def verify(assertion, audience)
48
+ http = Net::HTTP.new(@server, 443)
49
+ http.use_ssl = true
50
+
51
+ verification = Net::HTTP::Post.new(@path)
52
+ verification.set_form_data(assertion: assertion, audience: audience)
53
+
54
+ response = http.request(verification)
55
+ raise "Unsuccessful response from #{@server}: #{response}" unless response.kind_of? Net::HTTPSuccess
56
+ authentication = JSON.parse(response.body)
57
+
58
+ # Authentication response is a JSON hash which must contain a 'status'
59
+ # of "okay" or "failure".
60
+ status = authentication['status']
61
+ raise "Unknown authentication status '#{status}'" unless %w{okay failure}.include? status
62
+
63
+ # An unsuccessful authentication response should contain a reason string.
64
+ raise "Assertion failure: #{authentication['reason']}" unless status == "okay"
65
+
66
+ # A successful response looks like the following:
67
+ # {
68
+ # "status": "okay",
69
+ # "email": "user@example.com",
70
+ # "audience": "https://service.example.com:443",
71
+ # "expires": 1234567890,
72
+ # "issuer": "persona.mozilla.com"
73
+ # }
74
+
75
+ auth_audience = authentication['audience']
76
+ raise "Persona assertion audience '#{auth_audience}' does not match verifier audience '#{audience}'" unless auth_audience == audience
77
+
78
+ expires = authentication['expires'] && Time.at(authentication['expires'].to_i/1000.0)
79
+ raise "Persona assertion expired at #{expires}" if expires && expires < Time.now
80
+
81
+ [authentication['email'], authentication['issuer']]
82
+ end
83
+ end
84
+ end
85
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: browserid-auth-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Greg Look
9
+ - Alex Kravets
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-03-04 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: railties
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '3.2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '3.2'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rspec-rails
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '2.11'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '2.11'
47
+ - !ruby/object:Gem::Dependency
48
+ name: simplecov
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: tzinfo
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: jquery-rails
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :runtime
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ description: ! " This gem provides a lightweight single-sign-on authentication
96
+ framework to\n a Rails application based on Mozilla's Persona service (see:\n
97
+ \ https://login.persona.org/about). Persona identifies users by email address\n
98
+ \ and authenticates them using the BrowserID protocol. This lets a client\n prove
99
+ they own an email address without exposing their browsing behaviors to\n the
100
+ identity provider. This also frees the application from needing to\n securely
101
+ handle and store user credentials.\n"
102
+ email:
103
+ - alex@slatestudio.com
104
+ executables: []
105
+ extensions: []
106
+ extra_rdoc_files: []
107
+ files:
108
+ - app/assets/javascripts/browserid.js.coffee
109
+ - app/views/shared/_browserid.html.erb
110
+ - lib/browserid/rails/base.rb
111
+ - lib/browserid/rails/helpers.rb
112
+ - lib/browserid/rails/version.rb
113
+ - lib/browserid/verifier/persona.rb
114
+ - lib/browserid-auth-rails.rb
115
+ - lib/browserid-rails.rb
116
+ - LICENSE
117
+ - README.md
118
+ homepage: https://github.com/alexkravets/browserid-auth-rails
119
+ licenses: []
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ segments:
131
+ - 0
132
+ hash: -465273068887906201
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ segments:
140
+ - 0
141
+ hash: -465273068887906201
142
+ requirements: []
143
+ rubyforge_project:
144
+ rubygems_version: 1.8.24
145
+ signing_key:
146
+ specification_version: 3
147
+ summary: Lightweight Rails authentication framework using the BrowserID protocol.
148
+ test_files: []