openid_login_generator 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/USAGE +23 -0
- data/openid_login_generator.rb +36 -0
- data/templates/README +116 -0
- data/templates/controller.rb +111 -0
- data/templates/controller.rb~ +111 -0
- data/templates/controller_test.rb +0 -0
- data/templates/helper.rb +2 -0
- data/templates/openid_login_system.rb +87 -0
- data/templates/user.rb +14 -0
- data/templates/user_test.rb +0 -0
- data/templates/users.yml +0 -0
- data/templates/view_login.rhtml +15 -0
- data/templates/view_logout.rhtml +10 -0
- data/templates/view_welcome.rhtml +9 -0
- metadata +66 -0
data/USAGE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
NAME
|
2
|
+
openid_login - creates a functional openid login system
|
3
|
+
|
4
|
+
SYNOPSIS
|
5
|
+
openid_login [Controller name]
|
6
|
+
|
7
|
+
Good names are Account Myaccount Security
|
8
|
+
|
9
|
+
DESCRIPTION
|
10
|
+
This generator creates a general purpose login system.
|
11
|
+
|
12
|
+
Included:
|
13
|
+
- a User model which stores OpenID authenticated users
|
14
|
+
- a Controller with login, welcome and logoff actions
|
15
|
+
- a mixin which lets you easily add advanced authentication
|
16
|
+
features to your abstract base controller
|
17
|
+
|
18
|
+
|
19
|
+
EXAMPLE
|
20
|
+
./script/generate openid_login Account
|
21
|
+
|
22
|
+
This will generate an Account controller with login and logout methods.
|
23
|
+
The model is always called User
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class OpenidLoginGenerator < Rails::Generator::NamedBase
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
|
5
|
+
# Login module, controller class, functional test, and helper.
|
6
|
+
m.template "openid_login_system.rb", "lib/openid_login_system.rb"
|
7
|
+
m.template "controller.rb", File.join("app/controllers", class_path, "#{file_name}_controller.rb")
|
8
|
+
m.template "controller_test.rb", File.join("test/functional", class_path, "#{file_name}_controller_test.rb")
|
9
|
+
m.template "helper.rb", File.join("app/helpers", class_path, "#{file_name}_helper.rb")
|
10
|
+
|
11
|
+
# Model class, unit test, fixtures, and example schema.
|
12
|
+
m.template "user.rb", "app/models/user.rb"
|
13
|
+
m.template "user_test.rb", "test/unit/user_test.rb"
|
14
|
+
m.template "users.yml", "test/fixtures/users.yml"
|
15
|
+
|
16
|
+
# Layout and stylesheet.
|
17
|
+
m.template "scaffold:layout.rhtml", "app/views/layouts/scaffold.rhtml"
|
18
|
+
m.template "scaffold:style.css", "public/stylesheets/scaffold.css"
|
19
|
+
|
20
|
+
# Views.
|
21
|
+
m.directory File.join("app/views", class_path, file_name)
|
22
|
+
login_views.each do |action|
|
23
|
+
m.template "view_#{action}.rhtml",
|
24
|
+
File.join("app/views", class_path, file_name, "#{action}.rhtml")
|
25
|
+
end
|
26
|
+
|
27
|
+
m.template "README", "README_LOGIN"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_accessor :controller_class_name
|
32
|
+
|
33
|
+
def login_views
|
34
|
+
%w(welcome login logout)
|
35
|
+
end
|
36
|
+
end
|
data/templates/README
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
== About
|
2
|
+
|
3
|
+
This is a port of the standard LoginGenerator to use OpenID for
|
4
|
+
authentication. It is distributed with the Ruby OpenID library.
|
5
|
+
|
6
|
+
Read more at:
|
7
|
+
* http://openidenabled.com
|
8
|
+
* http://openidenabled.com/openid/libraries/ruby
|
9
|
+
* http://openid.net
|
10
|
+
|
11
|
+
== Installation
|
12
|
+
|
13
|
+
If you are reading this, then you have installed the openid_login
|
14
|
+
system, but there are still a few things you have to do
|
15
|
+
manually. First open your app/controllers/application.rb and add
|
16
|
+
|
17
|
+
require_dependency "openid_login_system"
|
18
|
+
|
19
|
+
to the top of the file and include the login system with
|
20
|
+
|
21
|
+
include OpenidLoginSystem
|
22
|
+
|
23
|
+
The beginning of your ApplicationController.
|
24
|
+
It should look something like this :
|
25
|
+
|
26
|
+
require_dependency "openid_login_system"
|
27
|
+
|
28
|
+
class ApplicationController < ActionController::Base
|
29
|
+
include OpenidLoginSystem
|
30
|
+
model :user
|
31
|
+
|
32
|
+
After you have done the modifications the the AbstractController you can import
|
33
|
+
the user model into the database. This model is meant as an example and you
|
34
|
+
should extend it.
|
35
|
+
|
36
|
+
The model :user is required when you are hitting problems to the degree of
|
37
|
+
"Session could not be restored becuase not all items in it are known"
|
38
|
+
|
39
|
+
== Requirements
|
40
|
+
|
41
|
+
You need a database table corresponding to the User model.
|
42
|
+
|
43
|
+
mysql syntax:
|
44
|
+
CREATE TABLE users (
|
45
|
+
id int(11) NOT NULL auto_increment,
|
46
|
+
openid_url varchar(256) default NULL,
|
47
|
+
PRIMARY KEY (id)
|
48
|
+
);
|
49
|
+
�
|
50
|
+
postgres :
|
51
|
+
CREATE TABLE "users" (
|
52
|
+
�"id" SERIAL NOT NULL UNIQUE,
|
53
|
+
�"openid_url" VARCHAR(256),
|
54
|
+
�PRIMARY KEY("id")
|
55
|
+
) WITH OIDS;
|
56
|
+
|
57
|
+
sqlite:
|
58
|
+
CREATE TABLE 'users' (
|
59
|
+
'id' INTEGER PRIMARY KEY NOT NULL,
|
60
|
+
'openid_url' VARCHAR(256) DEFAULT NULL
|
61
|
+
);
|
62
|
+
|
63
|
+
Of course your user model can have any amount of extra fields. This is just a
|
64
|
+
starting point
|
65
|
+
|
66
|
+
== How to use it
|
67
|
+
|
68
|
+
Now you can go around and happily add "before_filter :login_required" to the
|
69
|
+
controllers which you would like to protect.
|
70
|
+
|
71
|
+
After integrating the login system with your rails application
|
72
|
+
navigate to your new controller's login method. There you may login
|
73
|
+
which will create a new User object if you've never logged in
|
74
|
+
before. After you are done you should have a look at your DB, and
|
75
|
+
you'll see the record for your User with the openid_url you entered.
|
76
|
+
|
77
|
+
|
78
|
+
== Tips & Tricks
|
79
|
+
|
80
|
+
How do I...
|
81
|
+
|
82
|
+
... access the user who is currently logged in
|
83
|
+
|
84
|
+
A: You can get the user id from the session using @session[:user_id]
|
85
|
+
Example:
|
86
|
+
|
87
|
+
@session[:user_id]
|
88
|
+
|
89
|
+
To get the User object:
|
90
|
+
|
91
|
+
user = User.find(@session[:user_id])
|
92
|
+
|
93
|
+
The OpenidController also has a find_user method
|
94
|
+
which will return the User object of the logged in user, or nil
|
95
|
+
if no user is logged in.
|
96
|
+
|
97
|
+
|
98
|
+
... restrict access to only a few methods?
|
99
|
+
|
100
|
+
A: Use before_filters build in scoping.
|
101
|
+
Example:
|
102
|
+
before_filter :login_required, :only => [:myaccount, :changepassword]
|
103
|
+
before_filter :login_required, :except => [:index]
|
104
|
+
|
105
|
+
... check if a user is logged-in in my views?
|
106
|
+
|
107
|
+
A: @session[:user_id] will tell you. Here is an example helper which you can use to make this more pretty:
|
108
|
+
Example:
|
109
|
+
def user?
|
110
|
+
!@session[:user_id].nil?
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "cgi"
|
3
|
+
|
4
|
+
# load the openid library
|
5
|
+
begin
|
6
|
+
require "rubygems"
|
7
|
+
require_gem "ruby-openid", ">= 1.0.2"
|
8
|
+
rescue LoadError
|
9
|
+
require "openid"
|
10
|
+
end
|
11
|
+
|
12
|
+
class <%= class_name %>Controller < ApplicationController
|
13
|
+
layout 'scaffold'
|
14
|
+
|
15
|
+
# process the login request, disover the openid server, and
|
16
|
+
# then redirect.
|
17
|
+
def login
|
18
|
+
openid_url = @params[:openid_url]
|
19
|
+
|
20
|
+
if @request.post?
|
21
|
+
request = consumer.begin(openid_url)
|
22
|
+
|
23
|
+
case request.status
|
24
|
+
when OpenID::SUCCESS
|
25
|
+
return_to = url_for(:action=> 'complete')
|
26
|
+
trust_root = url_for(:controller=>'')
|
27
|
+
|
28
|
+
url = request.redirect_url(trust_root, return_to)
|
29
|
+
redirect_to(url)
|
30
|
+
return
|
31
|
+
|
32
|
+
when OpenID::FAILURE
|
33
|
+
escaped_url = CGI::escape(openid_url)
|
34
|
+
flash[:notice] = "Could not find OpenID server for #{escaped_url}"
|
35
|
+
|
36
|
+
else
|
37
|
+
flash[:notice] = "An unknown error occured."
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# handle the openid server response
|
45
|
+
def complete
|
46
|
+
response = consumer.complete(@params)
|
47
|
+
|
48
|
+
case response.status
|
49
|
+
when OpenID::SUCCESS
|
50
|
+
|
51
|
+
@user = User.get(response.identity_url)
|
52
|
+
|
53
|
+
# create user object if one does not exist
|
54
|
+
if @user.nil?
|
55
|
+
@user = User.new(:openid_url => response.identity_url)
|
56
|
+
@user.save
|
57
|
+
end
|
58
|
+
|
59
|
+
# storing both the openid_url and user id in the session for for quick
|
60
|
+
# access to both bits of information. Change as needed.
|
61
|
+
@session[:user_id] = @user.id
|
62
|
+
|
63
|
+
flash[:notice] = "Logged in as #{CGI::escape(response.identity_url)}"
|
64
|
+
|
65
|
+
redirect_to :action => "welcome"
|
66
|
+
return
|
67
|
+
|
68
|
+
when OpenID::FAILURE
|
69
|
+
if response.identity_url
|
70
|
+
flash[:notice] = "Verification of #{CGI::escape(response.identity_url)} failed."
|
71
|
+
|
72
|
+
else
|
73
|
+
flash[:notice] = 'Verification failed.'
|
74
|
+
end
|
75
|
+
|
76
|
+
when OpenID::CANCEL
|
77
|
+
flash[:notice] = 'Verification cancelled.'
|
78
|
+
|
79
|
+
else
|
80
|
+
flash[:notice] = 'Unknown response from OpenID server.'
|
81
|
+
end
|
82
|
+
|
83
|
+
redirect_to :action => 'login'
|
84
|
+
end
|
85
|
+
|
86
|
+
def logout
|
87
|
+
@session[:user_id] = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
def welcome
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Get the OpenID::Consumer object.
|
96
|
+
def consumer
|
97
|
+
# create the OpenID store for storing associations and nonces,
|
98
|
+
# putting it in your app's db directory
|
99
|
+
store_dir = Pathname.new(RAILS_ROOT).join('db').join('openid-store')
|
100
|
+
store = OpenID::FilesystemStore.new(store_dir)
|
101
|
+
|
102
|
+
return OpenID::Consumer.new(@session, store)
|
103
|
+
end
|
104
|
+
|
105
|
+
# get the logged in user object
|
106
|
+
def find_user
|
107
|
+
return nil if session[:user_id].nil?
|
108
|
+
User.find(session[:user_id])
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "cgi"
|
3
|
+
|
4
|
+
# load the openid library
|
5
|
+
begin
|
6
|
+
require "rubygems"
|
7
|
+
require_gem "ruby-openid", ">= 1.0"
|
8
|
+
rescue LoadError
|
9
|
+
require "openid"
|
10
|
+
end
|
11
|
+
|
12
|
+
class <%= class_name %>Controller < ApplicationController
|
13
|
+
layout 'scaffold'
|
14
|
+
|
15
|
+
# process the login request, disover the openid server, and
|
16
|
+
# then redirect.
|
17
|
+
def login
|
18
|
+
openid_url = @params[:openid_url]
|
19
|
+
|
20
|
+
if @request.post?
|
21
|
+
request = consumer.begin(openid_url)
|
22
|
+
|
23
|
+
case request.status
|
24
|
+
when OpenID::SUCCESS
|
25
|
+
return_to = url_for(:action=> 'complete')
|
26
|
+
trust_root = url_for(:controller=>'')
|
27
|
+
|
28
|
+
url = request.redirect_url(trust_root, return_to)
|
29
|
+
redirect_to(url)
|
30
|
+
return
|
31
|
+
|
32
|
+
when OpenID::FAILURE
|
33
|
+
escaped_url = CGI::escape(openid_url)
|
34
|
+
flash[:notice] = "Could not find OpenID server for #{escaped_url}"
|
35
|
+
|
36
|
+
else
|
37
|
+
flash[:notice] = "An unknown error occured."
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# handle the openid server response
|
45
|
+
def complete
|
46
|
+
response = consumer.complete(@params)
|
47
|
+
|
48
|
+
case response.status
|
49
|
+
when OpenID::SUCCESS
|
50
|
+
|
51
|
+
@user = User.get(response.identity_url)
|
52
|
+
|
53
|
+
# create user object if one does not exist
|
54
|
+
if @user.nil?
|
55
|
+
@user = User.new(:openid_url => response.identity_url)
|
56
|
+
@user.save
|
57
|
+
end
|
58
|
+
|
59
|
+
# storing both the openid_url and user id in the session for for quick
|
60
|
+
# access to both bits of information. Change as needed.
|
61
|
+
@session[:user_id] = @user.id
|
62
|
+
|
63
|
+
flash[:notice] = "Logged in as #{CGI::escape(response.identity_url)}"
|
64
|
+
|
65
|
+
redirect_to :action => "welcome"
|
66
|
+
return
|
67
|
+
|
68
|
+
when OpenID::FAILURE
|
69
|
+
if response.identity_url
|
70
|
+
flash[:notice] = "Verification of #{CGI::escape(response.identity_url)} failed."
|
71
|
+
|
72
|
+
else
|
73
|
+
flash[:notice] = 'Verification failed.'
|
74
|
+
end
|
75
|
+
|
76
|
+
when OpenID::CANCEL
|
77
|
+
flash[:notice] = 'Verification cancelled.'
|
78
|
+
|
79
|
+
else
|
80
|
+
flash[:notice] = 'Unknown response from OpenID server.'
|
81
|
+
end
|
82
|
+
|
83
|
+
redirect_to :action => 'login'
|
84
|
+
end
|
85
|
+
|
86
|
+
def logout
|
87
|
+
@session[:user_id] = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
def welcome
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Get the OpenID::Consumer object.
|
96
|
+
def consumer
|
97
|
+
# create the OpenID store for storing associations and nonces,
|
98
|
+
# putting it in your app's db directory
|
99
|
+
store_dir = Pathname.new(RAILS_ROOT).join('db').join('openid-store')
|
100
|
+
store = OpenID::FilesystemStore.new(store_dir)
|
101
|
+
|
102
|
+
return OpenID::Consumer.new(@session, store)
|
103
|
+
end
|
104
|
+
|
105
|
+
# get the logged in user object
|
106
|
+
def find_user
|
107
|
+
return nil if session[:user_id].nil?
|
108
|
+
User.find(session[:user_id])
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
File without changes
|
data/templates/helper.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require_dependency "user"
|
2
|
+
|
3
|
+
module OpenidLoginSystem
|
4
|
+
|
5
|
+
protected
|
6
|
+
|
7
|
+
# overwrite this if you want to restrict access to only a few actions
|
8
|
+
# or if you want to check if the user has the correct rights
|
9
|
+
# example:
|
10
|
+
#
|
11
|
+
# # only allow nonbobs
|
12
|
+
# def authorize?(user)
|
13
|
+
# user.login != "bob"
|
14
|
+
# end
|
15
|
+
def authorize?(user)
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
# overwrite this method if you only want to protect certain actions of the controller
|
20
|
+
# example:
|
21
|
+
#
|
22
|
+
# # don't protect the login and the about method
|
23
|
+
# def protect?(action)
|
24
|
+
# if ['action', 'about'].include?(action)
|
25
|
+
# return false
|
26
|
+
# else
|
27
|
+
# return true
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
def protect?(action)
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
# login_required filter. add
|
35
|
+
#
|
36
|
+
# before_filter :login_required
|
37
|
+
#
|
38
|
+
# if the controller should be under any rights management.
|
39
|
+
# for finer access control you can overwrite
|
40
|
+
#
|
41
|
+
# def authorize?(user)
|
42
|
+
#
|
43
|
+
def login_required
|
44
|
+
|
45
|
+
if not protect?(action_name)
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
|
49
|
+
if @session[:user_id] and authorize?(User.find(@session[:user_id]))
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
|
53
|
+
# store current location so that we can
|
54
|
+
# come back after the user logged in
|
55
|
+
store_location
|
56
|
+
|
57
|
+
# call overwriteable reaction to unauthorized access
|
58
|
+
access_denied
|
59
|
+
return false
|
60
|
+
end
|
61
|
+
|
62
|
+
# overwrite if you want to have special behavior in case the user is not authorized
|
63
|
+
# to access the current operation.
|
64
|
+
# the default action is to redirect to the login screen
|
65
|
+
# example use :
|
66
|
+
# a popup window might just close itself for instance
|
67
|
+
def access_denied
|
68
|
+
redirect_to :controller=>"/<%= file_name %>", :action =>"login"
|
69
|
+
end
|
70
|
+
|
71
|
+
# store current uri in the session.
|
72
|
+
# we can return to this location by calling return_location
|
73
|
+
def store_location
|
74
|
+
@session[:return_to] = @request.request_uri
|
75
|
+
end
|
76
|
+
|
77
|
+
# move to the last store_location call or to the passed default one
|
78
|
+
def redirect_back_or_default(default)
|
79
|
+
if @session[:return_to].nil?
|
80
|
+
redirect_to default
|
81
|
+
else
|
82
|
+
redirect_to_url @session[:return_to]
|
83
|
+
@session[:return_to] = nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
data/templates/user.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
# this model expects a certain database layout and its based on the name/login pattern.
|
3
|
+
class User < ActiveRecord::Base
|
4
|
+
|
5
|
+
def self.get(openid_url)
|
6
|
+
find_first(["openid_url = ?", openid_url])
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
validates_uniqueness_of :openid_url, :on => :create
|
13
|
+
validates_presence_of :openid_url
|
14
|
+
end
|
File without changes
|
data/templates/users.yml
ADDED
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%%= start_form_tag :action=> "login" %>
|
2
|
+
|
3
|
+
<div title="Account login" id="loginform" class="form">
|
4
|
+
<h3>Please login</h3>
|
5
|
+
|
6
|
+
<label for="user_login">Login:</label><br/>
|
7
|
+
<input type="text" name="openid_url" id="openid_url" size="30" value="<%= @login %>"/><br/>
|
8
|
+
|
9
|
+
<br/>
|
10
|
+
<input type="submit" name="login" value="Login »" class="primary" />
|
11
|
+
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<%%= end_form_tag %>
|
15
|
+
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: openid_login_generator
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.1"
|
7
|
+
date: 2006-06-12 00:00:00 -07:00
|
8
|
+
summary: "[Rails] OpenID Login generator."
|
9
|
+
require_paths:
|
10
|
+
- .
|
11
|
+
email: brian@janrain.com
|
12
|
+
homepage: http://wiki.rubyonrails.org/rails/pages/OpenidLoginGenerator
|
13
|
+
rubyforge_project:
|
14
|
+
description: Generates Rails code implementing an OpenID based login system for your Rails app. Based on the original Rails Login Generator.
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
authors:
|
29
|
+
- Brian Ellin, JanRain Inc.
|
30
|
+
files:
|
31
|
+
- templates/controller.rb
|
32
|
+
- templates/README
|
33
|
+
- templates/user_test.rb
|
34
|
+
- templates/helper.rb
|
35
|
+
- templates/user.rb
|
36
|
+
- templates/view_login.rhtml
|
37
|
+
- templates/users.yml
|
38
|
+
- templates/view_logout.rhtml
|
39
|
+
- templates/controller.rb~
|
40
|
+
- templates/view_welcome.rhtml
|
41
|
+
- templates/controller_test.rb
|
42
|
+
- templates/openid_login_system.rb
|
43
|
+
- USAGE
|
44
|
+
- openid_login_generator.rb
|
45
|
+
test_files: []
|
46
|
+
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
extra_rdoc_files: []
|
50
|
+
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
requirements: []
|
56
|
+
|
57
|
+
dependencies:
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: ruby-openid
|
60
|
+
version_requirement:
|
61
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.0.2
|
66
|
+
version:
|