browserid-rails 0.4.0

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.
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,141 @@
1
+ # BrowserID::Rails
2
+
3
+ This gem provides a simple authentication structure to a Rails application
4
+ based on Mozilla's BrowserID protocol and Persona service. Users are uniquely
5
+ authenticated by email address using public-key cryptography. The advantage of
6
+ this is that the rails application does not need to worry about storing or
7
+ securing user passwords.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'browserid-rails'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install browserid-rails
22
+
23
+ ## Usage
24
+
25
+ To use this gem once it is installed, it must be integrated into your Rails
26
+ application. The following sections cover the gem configuration, controller
27
+ integration, and view integration.
28
+
29
+ ### Configuration
30
+
31
+ There are several configuration options available. There are a number of default
32
+ assumptions about the application, which may be overridden as needed.
33
+ Configuration settings are properties of `config.browserid`.
34
+
35
+ * `user_model` - The name of the ActiveModel class for application users.
36
+ The default is `"User"`.
37
+ * `email_field` - The name of the attribute on the user model which contains
38
+ the user's email. The default is `"email"`.
39
+ * `session_variable` - The location the authenticated email is stored in the
40
+ client's session. The default is `:browserid_email`.
41
+ * `verifier` - The type of verifier to use to authenticate client BrowserID
42
+ assertions. The default is `:persona`, which sends the request to Mozilla's
43
+ Persona verification service. In the future, `:local` will enable local
44
+ verification code. Alternately, this configuration option may be set to any
45
+ class which responds to `#verify(assertion)` with the verified email and
46
+ identity provider on success and raises an error on failure.
47
+ * `audience` - The BrowserID audience to authenticate to. This should consist
48
+ of a URI string containing the scheme (protocol), authority, and port of the
49
+ service (e.g., `"https://app.example.com:443"`). By default, the audience is
50
+ not hardcoded and the properties of the request object are used to construct
51
+ it dynamically. This gives greater flexibility while developing, but is also
52
+ a minor security risk. In production, this should be configured to a fixed
53
+ value.
54
+
55
+ ### Controller Integration
56
+
57
+ The `BrowserID::Rails::Base` module makes several controller methods available
58
+ to interact with the authentication system. To access information, use one of:
59
+
60
+ * `browserid_email` - Returns the BrowserID-authenticated email address, if any.
61
+ * `current_user` - Retrieves the model for the currently authenticated user, if
62
+ there is an authenticated email and a matching user exists.
63
+ * `authenticated?` - Returns true if there is a current user.
64
+
65
+ These methods are also available in views as helpers.
66
+
67
+ To control authentication, the app should have a `SessionsController` which
68
+ connects the in-browser authentication code to the server. The gem provides
69
+ these methods:
70
+
71
+ * `login_browserid` - Sets the given string as the authenticated email.
72
+ * `logout_browserid` - Clears the current authenticated email.
73
+ * `verify_browserid` - Uses the configured verifier to confirm a BrowserID
74
+ assertion is correct for the service audience.
75
+ * `respond_to_browserid` - Wraps `verify_browserid` in logging and error
76
+ handling logic and generates controller responses to a `POST` assertion.
77
+
78
+ Implementing the required methods for `SessionsController` is straightforward:
79
+
80
+ # POST /login
81
+ def create
82
+ respond_to_browserid
83
+ end
84
+
85
+ # POST /logout
86
+ def destroy
87
+ logout_browserid
88
+ head :ok
89
+ end
90
+
91
+ TODO: write generator to create routes and session controller
92
+
93
+ ### Layout Integration
94
+
95
+ The BrowserID javascript library needs to be loaded on your application pages.
96
+ There are two steps to accomplish this:
97
+
98
+ First, the coffeescript asset file needs to be loaded. In the
99
+ `app/assets/javascripts/application.js` manifest, add the following line:
100
+
101
+ //= require browserid
102
+
103
+ Second, the scripts need to be setup in your pages' `<head>` section. The
104
+ `setup_browserid` helper method takes care of this for you and gives a couple
105
+ of ways to control its behavior:
106
+
107
+ <!-- Perform basic BrowserID setup in the head section -->
108
+ <%= setup_browserid %>
109
+
110
+ <!-- Setup BrowserID with alert debugging -->
111
+ <%= setup_browserid debug: true %>
112
+
113
+ <!-- Setup BrowserID with a custom handler -->
114
+ <%= setup_browserid do %>
115
+ browserid.onLogin = function (data, status, xhr) {
116
+ // ...
117
+ }
118
+ <% end %>
119
+
120
+ Once that's accomplished, the app is ready to use BrowserID for authentication.
121
+ To add login and logout links to the site, use the `login_link` and
122
+ `logout_link` helpers. These accept optional link text and targets as parameters:
123
+
124
+ <%= login_link "Login with Persona" %>
125
+
126
+ <%= login_link "Login", auth_path %>
127
+
128
+ If the path is not provided, the link helpers will use `login_path` and
129
+ `logout_path` if they are available, otherwise the link targets will be `#`.
130
+ The coffeescript assets add on-click handlers to the links which trigger the
131
+ Persona code to request new assertions or destroy existing ones.
132
+
133
+ TODO: include Persona branding assets
134
+
135
+ ## Contributing
136
+
137
+ 1. Fork it
138
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
139
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
140
+ 4. Push to the branch (`git push origin my-new-feature`)
141
+ 5. Create new Pull Request
@@ -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 result: #{status} #{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 #{err} - #{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 result: #{status} #{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 #{err} - #{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,41 @@
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
+ config.before_configuration do
12
+ BrowserIDConfig = Struct.new :user_model, :email_field, :session_variable, :verifier, :audience
13
+
14
+ config.browserid = BrowserIDConfig.new
15
+ config.browserid.user_model = 'User'
16
+ config.browserid.email_field = 'email'
17
+ config.browserid.session_variable = :browserid_email
18
+ config.browserid.verifier = :persona
19
+ # config.browserid.audience should only be set in production
20
+ end
21
+
22
+ initializer "browserid-rails.extend" do |app|
23
+ ActionController::Base.send :include, BrowserID::Rails::Base
24
+ ActionView::Base.send :include, BrowserID::Rails::Helpers
25
+ end
26
+
27
+ config.after_initialize do
28
+ cfg = config.browserid
29
+
30
+ # Replace type symbol with constructed verifier.
31
+ if cfg.verifier == :persona
32
+ cfg.verifier = BrowserID::Verifier::Persona.new
33
+ elsif cfg.verifier == :local
34
+ raise "Local BrowserID verification is not supported yet" # TODO
35
+ elsif !cfg.verifier.respond_to?(:verify)
36
+ raise "Unknown BrowserID verifier type #{cfg.verifier}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,130 @@
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_email, :current_user, :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
+ ##### AUTHENTICATION METHODS #####
29
+
30
+ # Public: Sets the given email address as the currently-authenticated user.
31
+ # The address is saved in the client's session.
32
+ #
33
+ # email - The String email address to consider authenticated.
34
+ def login_browserid(email)
35
+ session[browserid_config.session_variable] = email
36
+ end
37
+
38
+ # Public: Clears the saved email address for the currently-authenticated
39
+ # user. It is important to note that this does not remove the BrowserID
40
+ # assertion in the client's browser.
41
+ def logout_browserid
42
+ session[browserid_config.session_variable] = nil
43
+ end
44
+
45
+ # Public: Uses the configured verifier to check that a provided assertion
46
+ # is correct for the site audience.
47
+ #
48
+ # Returns the verified email, identity issuer, and audience on success.
49
+ # Raises an error with a failure message if the client was not
50
+ # successfully authenticated.
51
+ #
52
+ # Examples
53
+ #
54
+ # verify_browserid(assertion)
55
+ # # => "user@example.com", "persona.mozilla.com", "https://app.example.com:443"
56
+ #
57
+ def verify_browserid(assertion)
58
+ audience = browserid_config.audience
59
+ audience ||= "%s%s:%d" % [request.protocol, request.host, request.port]
60
+ browserid_config.verifier.verify(assertion, audience)
61
+ end
62
+
63
+ # Public: Handles a POST-ed BrowserID assertion, responding appropriately
64
+ # to the request. If successful, this logs-in the authenticated email and
65
+ # returns an OK status. If unsuccessful, it returns FORBIDDEN and an
66
+ # error message in the response body.
67
+ #
68
+ # Returns nothing.
69
+ #
70
+ # Examples
71
+ #
72
+ # # POST /login
73
+ # def create
74
+ # respond_to_browserid
75
+ # end
76
+ #
77
+ def respond_to_browserid
78
+ if params[:assertion].blank?
79
+ head :bad_request
80
+ else
81
+ email, issuer, audience = verify_browserid params[:assertion]
82
+ logger.info "Verified BrowserID assertion for #{email} issued by #{issuer} on #{audience}"
83
+ login_browserid email
84
+ head :ok
85
+ end
86
+ rescue StandardError => e
87
+ logger.warn "Failed to verify BrowserID assertion: #{e.message}"
88
+ render status: :forbidden, text: e.message
89
+ end
90
+
91
+
92
+
93
+ ##### HELPER METHODS #####
94
+
95
+ # Public: Gets the email address of the currently-authenticated user.
96
+ #
97
+ # Returns the authenticated email address String.
98
+ def browserid_email
99
+ session[browserid_config.session_variable]
100
+ end
101
+
102
+ # Public: Retrieves the user for the authenticated email address. This
103
+ # method uses the `browserid.user_model` and `browserid.email_field`
104
+ # config settings, which default to `User` and `email`.
105
+ #
106
+ # Returns the current authenticated user, or nil if no user exists.
107
+ def current_user
108
+ if browserid_email.nil?
109
+ nil
110
+ elsif @current_user
111
+ @current_user
112
+ else
113
+ config = browserid_config
114
+ user_model = config.user_model.constantize
115
+ find_method = "find_by_#{config.email_field}".intern
116
+
117
+ @current_user = user_model.send find_method, browserid_email
118
+ end
119
+ end
120
+
121
+ # Public: Determines whether the current client is authenticated as a
122
+ # registered User.
123
+ #
124
+ # Returns true if the client is authenticated and registered.
125
+ def authenticated?
126
+ !current_user.nil?
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,62 @@
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.
11
+ # :logout_path - String giving the path to POST logout
12
+ # notifications to.
13
+ # :debug - Boolean determining whether the browserid
14
+ # javascript will refresh the page or show an
15
+ # alert dialog.
16
+ # block - An optional block which can be used to provide additional
17
+ # content to be rendered inside the browserid setup script tag.
18
+ #
19
+ # Examples
20
+ #
21
+ # <!-- Perform basic BrowserID setup in the head section -->
22
+ # <%= setup_browserid %>
23
+ #
24
+ # <!-- Setup BrowserID with alert debugging -->
25
+ # <%= setup_browserid debug: true %>
26
+ #
27
+ # <!-- Setup BrowserID with a custom handler -->
28
+ # <%= setup_browserid do %>
29
+ # browserid.onLogin = function (data, status, xhr) {
30
+ # // ...
31
+ # }
32
+ # <% end %>
33
+ #
34
+ def setup_browserid(options={}, &block)
35
+ content_for :browserid_setup, capture(&block) if block_given?
36
+ render 'layouts/browserid', options: options
37
+ end
38
+
39
+ # Public: Renders a login link which will request a new authentication
40
+ # assertion from the BrowserID javascript code.
41
+ #
42
+ # text - String to use as link text (default: 'Login').
43
+ # path - String path to link to. If not provided, the `login_path` helper
44
+ # will be used if it exists. Otherwise, the link will be to '#'.
45
+ def login_link(text="Login", path=nil)
46
+ target = path || respond_to?(:login_path) && login_path || '#'
47
+ link_to text, target, class: :browserid_login
48
+ end
49
+
50
+ # Public: Renders a logout link which will clear the current BrowserID
51
+ # authentication status.
52
+ #
53
+ # text - String to use as link text (default: 'Logout').
54
+ # path - String path to link to. If not provided, the `logout_path` helper
55
+ # will be used if it exists. Otherwise, the link will be to '#'.
56
+ def logout_link(text="Logout", path=nil)
57
+ target = path || respond_to?(:logout_path) && logout_path || '#'
58
+ link_to text, target, class: :browserid_logout
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ module BrowserID
2
+ module Rails
3
+ VERSION = "0.4.0"
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,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: browserid-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Greg Look
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: railties
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
30
+ description:
31
+ email:
32
+ - greg@mvxcvi.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - app/views/layouts/_browserid.html.erb
38
+ - app/assets/javascripts/browserid.js.coffee
39
+ - lib/browserid/rails/helpers.rb
40
+ - lib/browserid/rails/version.rb
41
+ - lib/browserid/rails/base.rb
42
+ - lib/browserid/verifier/persona.rb
43
+ - lib/browserid-rails.rb
44
+ - LICENSE
45
+ - README.md
46
+ homepage: https://github.com/mvxcvi/browserid-rails
47
+ licenses: []
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ segments:
59
+ - 0
60
+ hash: -488449078399574217
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ segments:
68
+ - 0
69
+ hash: -488449078399574217
70
+ requirements: []
71
+ rubyforge_project:
72
+ rubygems_version: 1.8.24
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Rails authentication framework using Mozilla Persona and the BrowserID protocol.
76
+ test_files: []