thincloud-authentication 0.1.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.
Files changed (27) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +133 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/javascripts/thincloud/authentication/application.js +15 -0
  5. data/app/assets/stylesheets/thincloud/authentication/application.css +13 -0
  6. data/app/controllers/thincloud/authentication/application_controller.rb +6 -0
  7. data/app/controllers/thincloud/authentication/registrations_controller.rb +90 -0
  8. data/app/controllers/thincloud/authentication/sessions_controller.rb +23 -0
  9. data/app/helpers/thincloud/authentication/registrations_helper.rb +9 -0
  10. data/app/mailers/thincloud/authentication/registrations_mailer.rb +12 -0
  11. data/app/models/thincloud/authentication/identity.rb +80 -0
  12. data/app/views/thincloud/authentication/layouts/application.html.erb +14 -0
  13. data/app/views/thincloud/authentication/registrations/_registration_form.html.erb +69 -0
  14. data/app/views/thincloud/authentication/registrations/new.html.erb +1 -0
  15. data/app/views/thincloud/authentication/registrations_mailer/verification_token.text.erb +5 -0
  16. data/app/views/thincloud/authentication/sessions/_login_form.html.erb +46 -0
  17. data/app/views/thincloud/authentication/sessions/new.html.erb +22 -0
  18. data/config/routes.rb +14 -0
  19. data/db/migrate/20120918233329_create_thincloud_authentication_identities.rb +19 -0
  20. data/lib/tasks/thincloud-authentication_tasks.rake +4 -0
  21. data/lib/thincloud-authentication.rb +9 -0
  22. data/lib/thincloud/authentication/authenticatable_controller.rb +64 -0
  23. data/lib/thincloud/authentication/configuration.rb +20 -0
  24. data/lib/thincloud/authentication/engine.rb +67 -0
  25. data/lib/thincloud/authentication/identifiable_user.rb +9 -0
  26. data/lib/thincloud/authentication/version.rb +5 -0
  27. metadata +287 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 New Leaders
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # Thincloud::Authentication
2
+
3
+ [![Build Status](https://secure.travis-ci.org/newleaders/thincloud-authentication.png)](http://travis-ci.org/newleaders/thincloud-authentication) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/newleaders/thincloud-authentication)
4
+
5
+ ## Description
6
+
7
+ A Rails Engine to provide authentication for Thincloud applications.
8
+
9
+ ## Requirements
10
+
11
+ This gem requires Rails 3.2+ and has been tested on the following versions:
12
+
13
+ * 3.2
14
+
15
+ This gem has been tested against the following Ruby versions:
16
+
17
+ * MRI 1.9.2
18
+ * MRI 1.9.3
19
+ * JRuby 1.6+ (with `JRUBY_OPTS=--1.9`)
20
+ * Rubinius 2.0.0dev (with `RBXOPT=-X19`)
21
+
22
+ This gem has been tested against the following database versions:
23
+
24
+ * MySQL 5.0, 5.5
25
+ * PostgreSQL 9.1, 9.2
26
+ * SQLite 3
27
+
28
+
29
+ ## Installation
30
+
31
+ Add this line to your application's Gemfile:
32
+
33
+ ``` ruby
34
+ gem "thincloud-authentication"
35
+ ```
36
+
37
+ * Run `bundle`
38
+ * Copy the migrations and prepare your databases:
39
+
40
+ ```
41
+ $ rake thincloud_authentication:install:migrations db:migrate db:test:prepare
42
+ ```
43
+
44
+ * Mount the engine in your `config/routes.rb` file:
45
+
46
+ ```ruby
47
+ mount Thincloud::Authentication::Engine => "/auth", as: "auth_engine"
48
+ ```
49
+
50
+ Using the example above, you may now login or signup at [http://lvh.me:3000/auth](http://lvh.me:3000/auth).
51
+
52
+ ### Prerequisites
53
+
54
+ The following must be true for `thincloud-authentication` to operate properly:
55
+
56
+ * A `root_url` must be defined in `config/routes.rb`
57
+ * A `User` model must exist
58
+
59
+
60
+ ## Configuration
61
+
62
+ The `Thincloud::Authentication` module accepts a `configure` block with options to customize the engine behavior.
63
+
64
+
65
+ ### Mailers
66
+
67
+ Set the `mailer_sender` option to customize the "From" address of the emails sent from the system:
68
+
69
+ ```ruby
70
+ Thincloud::Authentication.configure do |config|
71
+ config.mailer_sender = "app@example.com"
72
+ end
73
+ ```
74
+
75
+
76
+ ### Additional provider strategies
77
+
78
+ Add a key to the `providers` hash with the name of the strategy, followed by additional options for `scopes` and `fields` as needed. Additionally, you will need to provide environment variables (prefixed with the provider name), with the `consumer_key` and `consumer_secret` values from your OAuth provider.
79
+
80
+ To enable the [LinkedIn](https://github.com/skorks/omniauth-linkedin) provider:
81
+
82
+ * Provide values for `ENV["LINKEDIN_CONSUMER_KEY"]` and `ENV["LINKEDIN_CONSUMER_SECRET"]`
83
+ * Add the file `config/initializers/thincloud_authentication.rb` with the following contents:
84
+
85
+ ```ruby
86
+ Thincloud::Authentication.configure do |config|
87
+ config.providers[:linkedin] = {
88
+ scopes: "r_emailaddress r_basicprofile",
89
+ fields: ["id", "email-address", "first-name", "last-name", "headline",
90
+ "industry", "picture-url", "location", "public-profile-url"]
91
+ }
92
+ end
93
+ ```
94
+
95
+
96
+ ### Vanity Routes
97
+
98
+ If you want to customize the routes (remove the `/auth` prefix), you may add the following to your `config/routes.rb` file:
99
+
100
+ ```ruby
101
+ get "signup", to: "thincloud/authentication/registrations#new", as: "signup"
102
+ get "login", to: "thincloud/authentication/sessions#new", as: "login"
103
+ delete "logout", to: "thincloud/authentication/sessions#destroy", as: "logout"
104
+ ```
105
+
106
+ Using the example above, you will have the following routes locally:
107
+
108
+ * `signup_url` points to "/signup"
109
+ * `login_url` points to "/login"
110
+ * `logout_url` points to "/logout" - Make sure to use the `delete` method to logout.
111
+
112
+
113
+ ## TODO
114
+
115
+ * Add "forgot password" functionality
116
+ * Add multiple, configurable strategy options
117
+ * Add a configuration option to customize the mailers
118
+
119
+
120
+ ## Contributing
121
+
122
+ 1. [Fork it](https://github.com/newleaders/thincloud-authentication/fork_select)
123
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
124
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
125
+ 4. Push to the branch (`git push origin my-new-feature`)
126
+ 5. [Create a Pull Request](https://github.com/newleaders/thincloud-authentication/pull/new)
127
+
128
+
129
+ ## License
130
+
131
+ * Freely distributable and licensed under the [MIT license](http://newleaders.mit-license.org/2012/license.html).
132
+ * Copyright (c) 2012 New Leaders ([opensource@newleaders.com](opensource@newleaders.com))
133
+ * [https://newleaders.com](https://newleaders.com)
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Thincloud::Authentication'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,6 @@
1
+ module Thincloud::Authentication
2
+ # Public: Primary controller settings and helpers for the engine.
3
+ class ApplicationController < ActionController::Base
4
+ layout "application"
5
+ end
6
+ end
@@ -0,0 +1,90 @@
1
+ require_dependency "thincloud/authentication/application_controller"
2
+
3
+ module Thincloud::Authentication
4
+ # Public: Handle OmniAuth callbacks.
5
+ class RegistrationsController < ApplicationController
6
+ before_filter :extract_identity, only: :create
7
+
8
+ def new
9
+ @identity = Identity.new
10
+ end
11
+
12
+ def create
13
+ # identity exists
14
+ if @identity.present?
15
+ login_as @identity.user
16
+ redirect_to main_app.root_url, notice: "You have been logged in."
17
+ # new identity for current_user
18
+ elsif current_user
19
+ add_omniauth_identity_to_current_user
20
+ redirect_to main_app.root_url, notice: "You have been logged in."
21
+ # failed identity login
22
+ elsif invalid_identity_credentials?
23
+ redirect_to auth_failure_url message: "invalid_credentials",
24
+ strategy: "identity"
25
+ # create a new identity
26
+ else
27
+ @identity = create_identity_from_request
28
+ render :new and return if @identity.errors.any?
29
+
30
+ if omniauth
31
+ login_as @identity.user
32
+ else
33
+ RegistrationsMailer.verification_token(@identity).deliver
34
+ flash[:alert] = "Check your email to verify your registration."
35
+ end
36
+ redirect_to main_app.root_url
37
+ end
38
+ end
39
+
40
+ def verify
41
+ identity = Identity.verify!(params[:token])
42
+ login_as identity.user
43
+ redirect_to main_app.root_url,
44
+ notice: "Thank you! Your registration has been verified."
45
+ end
46
+
47
+ private
48
+
49
+ # Private: Accessor for OmniAuth environment.
50
+ #
51
+ # Returns: An instance of `OmniAuth::InfoHash` or `nil`.
52
+ def omniauth
53
+ request.env["omniauth.auth"]
54
+ end
55
+
56
+ # Private: Set an instance varible if an `Identity` if present.
57
+ #
58
+ # Returns: An instance of `Identity` or `nil`.
59
+ def extract_identity
60
+ @identity = Identity.find_omniauth(omniauth) if omniauth
61
+ end
62
+
63
+ # Private: Determine if the request is from an invalid Identity login.
64
+ #
65
+ # Returns: Boolean.
66
+ def invalid_identity_credentials?
67
+ params[:provider] == "identity" && params.has_key?(:auth_key)
68
+ end
69
+
70
+ # Private: Add a new identity to the `current_user` from OmniAuth.
71
+ #
72
+ # Returns: Boolean.
73
+ def add_omniauth_identity_to_current_user
74
+ current_user.identities.build.apply_omniauth(omniauth).save
75
+ end
76
+
77
+ # Private: Create a new identity from submitted params or OmniAuth.
78
+ #
79
+ # Returns: An instance of `Identity`.
80
+ def create_identity_from_request
81
+ # params[:identity] exists when creating a local identity provider
82
+ Identity.new(params[:identity]).tap do |identity|
83
+ identity.user = User.create
84
+ # omniauth exists if coming from a 3rd party provider like LinkedIn
85
+ identity.apply_omniauth(omniauth) if omniauth
86
+ identity.save
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,23 @@
1
+ require_dependency "thincloud/authentication/application_controller"
2
+
3
+ module Thincloud::Authentication
4
+ # Public: Handle login/logout behavior.
5
+ class SessionsController < ApplicationController
6
+ before_filter :authenticate!, only: [:authenticated]
7
+
8
+ def new
9
+ redirect_to main_app.root_url if logged_in?
10
+ @identity = Identity.new
11
+ end
12
+
13
+ def destroy
14
+ logout
15
+ redirect_to main_app.root_url, notice: "You have been logged out."
16
+ end
17
+
18
+ def authenticated
19
+ # dummy method to test the :authenticate! before_filter
20
+ render text: "Authenticated!"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ module Thincloud::Authentication
2
+ module RegistrationsHelper
3
+
4
+ def form_error_class_for(form, field)
5
+ "error" if form.object.errors[field].present?
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module Thincloud::Authentication
2
+ # Public: Email methods for Registration events
3
+ class RegistrationsMailer < ActionMailer::Base
4
+ default from: Thincloud::Authentication.configuration.mailer_sender
5
+
6
+ # New registration verification token
7
+ def verification_token(identity)
8
+ @identity = identity
9
+ mail to: @identity.email, subject: "Identity Verification"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,80 @@
1
+ module Thincloud::Authentication
2
+ # Public: This class represents a User identity (name, email, login provider)
3
+ class Identity < ::OmniAuth::Identity::Models::ActiveRecord
4
+ belongs_to :user
5
+
6
+ # Limit the ability to mass-assign sensitive fields.
7
+ attr_accessible :name, :email, :password, :password_confirmation
8
+
9
+ validates :name, presence: true
10
+ validates :email, presence: true, uniqueness: true, format: /@/
11
+
12
+ # Ensure that a `verification_token` exists for new records.
13
+ after_initialize do
14
+ self.verification_token = SecureRandom.urlsafe_base64 if new_record?
15
+ end
16
+
17
+ # Only validate password if the 'provider' is 'identity'.
18
+ before_validation do
19
+ self.password_digest = 0 unless provider == "identity"
20
+ end
21
+
22
+ # Public: Use a helpful attribute name when displaying errors.
23
+ def self.human_attribute_name(attr, options={})
24
+ attr == :password_digest ? "Password" : super
25
+ end
26
+
27
+ # Public: Find an `Identity` by OmniAuth parameters.
28
+ #
29
+ # omniauth - An instance of `OmniAuth::AuthHash`
30
+ #
31
+ # Returns: An instance of `Identity` or `nil`.
32
+ def self.find_omniauth(omniauth)
33
+ find_by_provider_and_uid omniauth["provider"], omniauth["uid"]
34
+ end
35
+
36
+ # Public: Mark the `Identity` as having been verified.
37
+ #
38
+ # token - A String containing the `verification_token` to look up.
39
+ #
40
+ # Returns: An instance of the found `Identity`.
41
+ # Raises: ActiveRecord::RecordNotFound if the `token` cannot be retrieved.
42
+ def self.verify!(token)
43
+ find_by_verification_token!(token).tap do |identity|
44
+ # ensure 'uid' exists, needed for 'identity' provider
45
+ identity.uid = identity.id if identity.uid.blank?
46
+ identity.verification_token = nil
47
+ identity.verified_at = Time.zone.now
48
+ identity.save
49
+ end
50
+ end
51
+
52
+ # Public: Shim to overcome odd behavior seen during testing with SQLite
53
+ def uid
54
+ read_attribute :uid
55
+ end
56
+
57
+ # Public: Indicate if the `Identity` has been verified.
58
+ #
59
+ # Returns: Boolean.
60
+ def verified?
61
+ verification_token.blank? && verified_at.present?
62
+ end
63
+
64
+ # Public: Apply attributes returned from OmniAuth.
65
+ #
66
+ # omniauth - An instance of `OmniAuth::AuthHash`.
67
+ def apply_omniauth(omniauth)
68
+ info = omniauth["info"]
69
+
70
+ user_name = %Q(#{info["first_name"]} #{info["last_name"]})
71
+ user_name.gsub!(/\s+/, " ").strip!
72
+
73
+ self.provider = omniauth["provider"]
74
+ self.uid = omniauth["uid"]
75
+ self.name = user_name if self.name.blank?
76
+ self.email = info["email"] if info["email"] && self.email.blank?
77
+ self
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Thincloud::Authentication</title>
5
+ <%= stylesheet_link_tag "thincloud/authentication/application", :media => "all" %>
6
+ <%= javascript_include_tag "thincloud/authentication/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,69 @@
1
+ <%= form_for @identity, url: registrations_path, html: { class: "form-horizontal" } do |f| %>
2
+ <fieldset>
3
+ <legend>Register</legend>
4
+
5
+ <% if @identity.errors.any? %>
6
+ <div class="alert alert-block alert-error">
7
+ <h4><i class="icon-warning-sign"></i> Error</h4>
8
+ Please check the following <%= pluralize @identity.errors.size, "item" %>:
9
+ </div>
10
+ <% end %>
11
+
12
+ <div class="control-group <%= form_error_class_for(f, :name) %>">
13
+ <%= f.label :name, "Name", class: "control-label" %>
14
+ <div class="controls">
15
+ <div class="input-prepend">
16
+ <span class="add-on"><i class="icon-user"></i></span>
17
+ <%= f.text_field :name %>
18
+ </div>
19
+ <%= content_tag :span, "#{:name.to_s.humanize} #{f.object.errors[:name].to_sentence}", class: "help-inline" %>
20
+ </div>
21
+ </div>
22
+
23
+
24
+ <div class="control-group <%= form_error_class_for(f, :email) %>">
25
+ <%= f.label :email, "Email", class: "control-label" %>
26
+ <div class="controls">
27
+ <div class="input-prepend">
28
+ <span class="add-on"><i class="icon-envelope"></i></span>
29
+ <%= f.email_field :email %>
30
+ </div>
31
+ <%= content_tag :span, "#{:email.to_s.humanize} #{f.object.errors[:email].to_sentence}", class: "help-inline" %>
32
+ </div>
33
+ </div>
34
+
35
+ <div class="control-group <%= form_error_class_for(f, :password_digest) %>">
36
+ <%= f.label :password, "Password", class: "control-label" %>
37
+ <div class="controls">
38
+ <div class="input-prepend">
39
+ <span class="add-on"><i class="icon-lock"></i></span>
40
+ <%= f.password_field :password %>
41
+ </div>
42
+ <%= content_tag :span, "#{:password.to_s.humanize} #{f.object.errors[:password_digest].to_sentence}", class: "help-inline" %>
43
+ </div>
44
+ </div>
45
+
46
+ <div class="control-group <%= form_error_class_for(f, :password) %>">
47
+ <%= f.label :password_confirmation, "Confirmation", class: "control-label" %>
48
+ <div class="controls">
49
+ <div class="input-prepend">
50
+ <span class="add-on"><i class="icon-lock"></i></span>
51
+ <%= f.password_field :password_confirmation %>
52
+ </div>
53
+ <%= content_tag :span, "#{:password.to_s.humanize} #{f.object.errors[:password].to_sentence}", class: "help-inline" %>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="control-group">
58
+ <div class="controls">
59
+ <%= button_tag type: "submit", class: "btn btn-large btn-primary" do %>
60
+ <i class="icon-ok icon-white"></i> Register
61
+ <% end %>
62
+
63
+ <%= link_to root_url, class: "btn btn-large" do %>
64
+ <i class="icon-remove"></i> Cancel
65
+ <% end %>
66
+ </div>
67
+ </div>
68
+ </fieldset>
69
+ <% end %>
@@ -0,0 +1 @@
1
+ <%= render "registration_form" %>
@@ -0,0 +1,5 @@
1
+ Welcome <%= @identity.email %>!
2
+
3
+ You can verify your account through the link below:
4
+
5
+ <%= verify_token_url(token: @identity.verification_token) %>
@@ -0,0 +1,46 @@
1
+ <%= form_tag auth_callback_url(provider: "identity"), class: "form-horizontal" do %>
2
+ <fieldset>
3
+ <legend>Login</legend>
4
+
5
+ <% if params[:message].present? %>
6
+ <div class="alert alert-block alert-error">
7
+ <h4><i class="icon-warning-sign"></i> Error</h4>
8
+ <%= params[:message].humanize %>
9
+ </div>
10
+ <% end %>
11
+
12
+ <div class="control-group">
13
+ <%= label_tag :auth_key, "Email", class: "control-label" %>
14
+ <div class="controls">
15
+ <div class="input-prepend">
16
+ <span class="add-on"><i class="icon-envelope"></i></span>
17
+ <%= email_field_tag :auth_key, params[:auth_key] %>
18
+ </div>
19
+ </div>
20
+ </div>
21
+
22
+ <div class="control-group">
23
+ <%= label_tag :password, "Password", class: "control-label" %>
24
+ <div class="controls">
25
+ <div class="input-prepend">
26
+ <span class="add-on"><i class="icon-lock"></i></span>
27
+ <%= password_field_tag :password %>
28
+ </div>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="control-group">
33
+ <div class="controls">
34
+ <%= button_tag type: "submit", class: "btn btn-large btn-primary" do %>
35
+ <i class="icon-ok icon-white"></i> Login
36
+ <% end %>
37
+
38
+ or
39
+
40
+ <%= link_to signup_url, class: "btn btn-large" do %>
41
+ <i class="icon-user"></i> Signup
42
+ <% end %>
43
+ </div>
44
+ </div>
45
+ </fieldset>
46
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <div class="tabbable">
2
+ <ul class="nav nav-tabs">
3
+ <li class="active">
4
+ <a href="#login" data-toggle="tab"><i class="icon-lock"></i> Login</a>
5
+ </li>
6
+ <li>
7
+ <a href="#register" data-toggle="tab"><i class="icon-user"></i> Register</a>
8
+ </li>
9
+ </ul>
10
+
11
+ <div class="tab-content">
12
+ <!-- Login -->
13
+ <div class="tab-pane active" id="login">
14
+ <%= render "login_form" %>
15
+ </div>
16
+
17
+ <!-- Register -->
18
+ <div class="tab-pane" id="register">
19
+ <%= render "thincloud/authentication/registrations/registration_form" %>
20
+ </div>
21
+ </div>
22
+ </div>
data/config/routes.rb ADDED
@@ -0,0 +1,14 @@
1
+ Thincloud::Authentication::Engine.routes.draw do
2
+ match ":provider/callback" => "registrations#create", as: "auth_callback"
3
+ get "failure", to: "sessions#new", as: "auth_failure"
4
+
5
+ get "login", to: "sessions#new", as: "login"
6
+ delete "logout", to: "sessions#destroy", as: "logout"
7
+ get "authenticated", to: "sessions#authenticated"
8
+
9
+ resources :registrations, only: [:new, :create]
10
+ get "signup", to: "registrations#new", as: "signup"
11
+ get "verify/:token", to: "registrations#verify", as: "verify_token"
12
+
13
+ root to: "sessions#new"
14
+ end
@@ -0,0 +1,19 @@
1
+ class CreateThincloudAuthenticationIdentities < ActiveRecord::Migration
2
+ def change
3
+ create_table :thincloud_authentication_identities do |t|
4
+ t.integer :user_id, null: false
5
+ t.string :provider, null: false, default: "identity"
6
+ t.string :uid
7
+ t.string :name, null: false
8
+ t.string :email, null: false
9
+ t.string :password_digest, null: false
10
+ t.string :verification_token
11
+ t.datetime :verified_at
12
+
13
+ t.timestamps
14
+ end
15
+ add_index :thincloud_authentication_identities, :user_id
16
+ add_index :thincloud_authentication_identities, [:provider, :uid], unique: true
17
+ add_index :thincloud_authentication_identities, :email
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :thincloud-authentication do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,9 @@
1
+ require "thincloud/authentication/configuration"
2
+ require "thincloud/authentication/engine"
3
+ require "thincloud/authentication/authenticatable_controller"
4
+ require "thincloud/authentication/identifiable_user"
5
+
6
+ module Thincloud
7
+ module Authentication
8
+ end
9
+ end
@@ -0,0 +1,64 @@
1
+ module Thincloud
2
+ module Authentication
3
+
4
+ module AuthenticatableController
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ helper_method :current_user
9
+ helper_method :logged_in?
10
+ end
11
+
12
+ protected
13
+
14
+ # Protected: The user that is currently logged in.
15
+ #
16
+ # This method is also available as a view helper.
17
+ #
18
+ # Returns: An instance of `User` or `nil`.
19
+ def current_user
20
+ return nil if session[:uid].blank?
21
+ @current_user ||= User.find(session[:uid])
22
+ end
23
+
24
+ # Protected: Determine if the current request has a logged in user.
25
+ #
26
+ # This method is also available as a view helper.
27
+ #
28
+ # Returns: Boolean.
29
+ def logged_in?
30
+ current_user.present?
31
+ end
32
+
33
+ # Protected: Require an authenticated user to perform an action.
34
+ #
35
+ # Use in a `before_filter`.
36
+ #
37
+ # Returns: Redirect if not logged in, otherwise `nil`.
38
+ def authenticate!
39
+ unless logged_in?
40
+ redirect_to login_url, alert: "You must be logged in to continue."
41
+ end
42
+ end
43
+
44
+ # Protected: Set the `current_user` to the provided `User` instance.
45
+ #
46
+ # user - An instance of `User` that has been authenticated.
47
+ #
48
+ # Returns: The `id` of the provided user.
49
+ def login_as(user)
50
+ reset_session # avoid session fixation
51
+ session[:uid] = user.id
52
+ end
53
+
54
+ # Protected: Clear the session of an authenticated user.
55
+ #
56
+ # Returns: A new empty session instance.
57
+ def logout
58
+ reset_session
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,20 @@
1
+ module Thincloud::Authentication
2
+ class << self
3
+ attr_accessor :configuration
4
+ end
5
+
6
+ def self.configure
7
+ self.configuration ||= Configuration.new
8
+ yield configuration
9
+ end
10
+
11
+ # Public: Configuration options for the Thincloud::Authentication module
12
+ class Configuration
13
+ attr_accessor :providers, :mailer_sender
14
+
15
+ def initialize
16
+ @providers = {}
17
+ @mailer_sender = "app@example.com"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,67 @@
1
+ module Thincloud
2
+ module Authentication
3
+ # Public: Initialize the Rails engine
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace Thincloud::Authentication
6
+
7
+ initializer "thincloud.authentication.omniauth.middleware" do |app|
8
+ require "omniauth"
9
+ require "omniauth-identity"
10
+
11
+ config = Thincloud::Authentication.configuration || Configuration.new
12
+ strategies = config.providers.keys
13
+ strategies.each { |strategy| require "omniauth-#{strategy}" }
14
+
15
+ app.middleware.use ::OmniAuth::Builder do
16
+
17
+ # always provide the Identity strategy
18
+ provider :identity, fields: [:email], model: Identity,
19
+ on_failed_registration: RegistrationsController.action(:new)
20
+
21
+ strategies.each do |strategy|
22
+ provider strategy, ENV["#{strategy.to_s.upcase}_CONSUMER_KEY"],
23
+ ENV["#{strategy.to_s.upcase}_CONSUMER_SECRET"],
24
+ fields: config.providers[strategy][:fields],
25
+ scope: config.providers[strategy][:scopes]
26
+ end
27
+ end
28
+ end
29
+
30
+ initializer "thincloud.authentication.omniauth.logger" do
31
+ ::OmniAuth.config.logger = ::Rails.logger
32
+ end
33
+
34
+ initializer "thincloud.authentication.omniauth.failure_endpoint" do
35
+ ::OmniAuth.config.on_failure = -> env do
36
+ ::OmniAuth::FailureEndpoint.new(env).redirect_to_failure
37
+ end
38
+ end
39
+
40
+ initializer "thincloud.authentication.omniauth.identity_redirects" do
41
+ # override default omniauth-identity forms
42
+ class ::OmniAuth::Strategies::Identity
43
+ def registration_form
44
+ redirect "/signup"
45
+ end
46
+
47
+ def request_phase
48
+ redirect "/login"
49
+ end
50
+ end
51
+ end
52
+
53
+ initializer "thincloud.authentication.user" do
54
+ ::User.send :include, Thincloud::Authentication::IdentifiableUser
55
+ end
56
+
57
+ initializer "thincloud.authentication.action_controller" do
58
+ ActionController::Base.send :include,
59
+ Thincloud::Authentication::AuthenticatableController
60
+ end
61
+
62
+ config.generators do |g|
63
+ g.test_framework :mini_test, spec: true, fixture: false
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,9 @@
1
+ module Thincloud::Authentication
2
+ module IdentifiableUser
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_many :identities, class_name: "Thincloud::Authentication::Identity"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module Thincloud
2
+ module Authentication
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,287 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thincloud-authentication
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Phil Cohen
9
+ - Robert Bousquet
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-09-23 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 3.2.8
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.8
31
+ - !ruby/object:Gem::Dependency
32
+ name: omniauth
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: 1.1.1
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.1.1
47
+ - !ruby/object:Gem::Dependency
48
+ name: omniauth-identity
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.0
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 1.1.0
63
+ - !ruby/object:Gem::Dependency
64
+ name: omniauth-linkedin
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: 0.0.8
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 0.0.8
79
+ - !ruby/object:Gem::Dependency
80
+ name: cane
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ~>
85
+ - !ruby/object:Gem::Version
86
+ version: 2.3.0
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ version: 2.3.0
95
+ - !ruby/object:Gem::Dependency
96
+ name: guard
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ~>
101
+ - !ruby/object:Gem::Version
102
+ version: 1.3.3
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 1.3.3
111
+ - !ruby/object:Gem::Dependency
112
+ name: minitest
113
+ requirement: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ~>
117
+ - !ruby/object:Gem::Version
118
+ version: 3.4.0
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ~>
125
+ - !ruby/object:Gem::Version
126
+ version: 3.4.0
127
+ - !ruby/object:Gem::Dependency
128
+ name: guard-minitest
129
+ requirement: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ~>
133
+ - !ruby/object:Gem::Version
134
+ version: 0.5.0
135
+ type: :development
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ~>
141
+ - !ruby/object:Gem::Version
142
+ version: 0.5.0
143
+ - !ruby/object:Gem::Dependency
144
+ name: minitest-rails
145
+ requirement: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ~>
149
+ - !ruby/object:Gem::Version
150
+ version: 0.1.3
151
+ type: :development
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ~>
157
+ - !ruby/object:Gem::Version
158
+ version: 0.1.3
159
+ - !ruby/object:Gem::Dependency
160
+ name: minitest-rails-shoulda
161
+ requirement: !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ version: 0.1.0
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ~>
173
+ - !ruby/object:Gem::Version
174
+ version: 0.1.0
175
+ - !ruby/object:Gem::Dependency
176
+ name: rb-fsevent
177
+ requirement: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ~>
181
+ - !ruby/object:Gem::Version
182
+ version: 0.9.1
183
+ type: :development
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ none: false
187
+ requirements:
188
+ - - ~>
189
+ - !ruby/object:Gem::Version
190
+ version: 0.9.1
191
+ - !ruby/object:Gem::Dependency
192
+ name: simplecov
193
+ requirement: !ruby/object:Gem::Requirement
194
+ none: false
195
+ requirements:
196
+ - - ~>
197
+ - !ruby/object:Gem::Version
198
+ version: 0.6.4
199
+ type: :development
200
+ prerelease: false
201
+ version_requirements: !ruby/object:Gem::Requirement
202
+ none: false
203
+ requirements:
204
+ - - ~>
205
+ - !ruby/object:Gem::Version
206
+ version: 0.6.4
207
+ - !ruby/object:Gem::Dependency
208
+ name: mocha
209
+ requirement: !ruby/object:Gem::Requirement
210
+ none: false
211
+ requirements:
212
+ - - ~>
213
+ - !ruby/object:Gem::Version
214
+ version: 0.12.4
215
+ type: :development
216
+ prerelease: false
217
+ version_requirements: !ruby/object:Gem::Requirement
218
+ none: false
219
+ requirements:
220
+ - - ~>
221
+ - !ruby/object:Gem::Version
222
+ version: 0.12.4
223
+ description: Rails Engine to provide authentication for Thincloud applications
224
+ email:
225
+ - pcohen@newleaders.com
226
+ - rbousquet@newleaders.com
227
+ executables: []
228
+ extensions: []
229
+ extra_rdoc_files: []
230
+ files:
231
+ - app/assets/javascripts/thincloud/authentication/application.js
232
+ - app/assets/stylesheets/thincloud/authentication/application.css
233
+ - app/controllers/thincloud/authentication/application_controller.rb
234
+ - app/controllers/thincloud/authentication/registrations_controller.rb
235
+ - app/controllers/thincloud/authentication/sessions_controller.rb
236
+ - app/helpers/thincloud/authentication/registrations_helper.rb
237
+ - app/mailers/thincloud/authentication/registrations_mailer.rb
238
+ - app/models/thincloud/authentication/identity.rb
239
+ - app/views/thincloud/authentication/layouts/application.html.erb
240
+ - app/views/thincloud/authentication/registrations/_registration_form.html.erb
241
+ - app/views/thincloud/authentication/registrations/new.html.erb
242
+ - app/views/thincloud/authentication/registrations_mailer/verification_token.text.erb
243
+ - app/views/thincloud/authentication/sessions/_login_form.html.erb
244
+ - app/views/thincloud/authentication/sessions/new.html.erb
245
+ - config/routes.rb
246
+ - db/migrate/20120918233329_create_thincloud_authentication_identities.rb
247
+ - lib/tasks/thincloud-authentication_tasks.rake
248
+ - lib/thincloud/authentication/authenticatable_controller.rb
249
+ - lib/thincloud/authentication/configuration.rb
250
+ - lib/thincloud/authentication/engine.rb
251
+ - lib/thincloud/authentication/identifiable_user.rb
252
+ - lib/thincloud/authentication/version.rb
253
+ - lib/thincloud-authentication.rb
254
+ - MIT-LICENSE
255
+ - Rakefile
256
+ - README.md
257
+ homepage: https://github.com/newleaders/thincloud-authentication
258
+ licenses: []
259
+ post_install_message:
260
+ rdoc_options: []
261
+ require_paths:
262
+ - lib
263
+ required_ruby_version: !ruby/object:Gem::Requirement
264
+ none: false
265
+ requirements:
266
+ - - ! '>='
267
+ - !ruby/object:Gem::Version
268
+ version: '0'
269
+ segments:
270
+ - 0
271
+ hash: 3364386958863775653
272
+ required_rubygems_version: !ruby/object:Gem::Requirement
273
+ none: false
274
+ requirements:
275
+ - - ! '>='
276
+ - !ruby/object:Gem::Version
277
+ version: '0'
278
+ segments:
279
+ - 0
280
+ hash: 3364386958863775653
281
+ requirements: []
282
+ rubyforge_project:
283
+ rubygems_version: 1.8.24
284
+ signing_key:
285
+ specification_version: 3
286
+ summary: Rails Engine to provide authentication for Thincloud applications
287
+ test_files: []