moro-repim 0.1.1
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/ChangeLog +4 -0
- data/README.rdoc +30 -0
- data/Rakefile +184 -0
- data/generators/relying_party/relying_party_generator.rb +114 -0
- data/generators/relying_party/templates/public/images/openid-login.gif +0 -0
- data/generators/relying_party/templates/public/stylesheets/repim.css +9 -0
- data/generators/relying_party/templates/sessions_controller.rb +4 -0
- data/generators/relying_party/templates/spec/application_controller_spec.rb +17 -0
- data/generators/relying_party/templates/spec/sessions_controller_spec.rb +78 -0
- data/generators/relying_party/templates/spec/sessions_routing_spec.rb +51 -0
- data/generators/relying_party/templates/spec/users_controller_spec.rb +98 -0
- data/generators/relying_party/templates/spec/users_routing_spec.rb +59 -0
- data/generators/relying_party/templates/users_controller.rb +21 -0
- data/generators/relying_party/templates/views/layouts/sessions.html.erb +18 -0
- data/generators/relying_party/templates/views/sessions/new.html.erb +13 -0
- data/generators/relying_party/templates/views/users/new.html.erb +23 -0
- data/lib/repim/application.rb +54 -0
- data/lib/repim/ax_attributes_adapter.rb +32 -0
- data/lib/repim/relying_party.rb +90 -0
- data/lib/repim/signup.rb +28 -0
- data/lib/repim.rb +3 -0
- data/rails/init.rb +5 -0
- metadata +97 -0
data/ChangeLog
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
= repim
|
3
|
+
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
Relying Party in minutes.
|
8
|
+
|
9
|
+
== Installation
|
10
|
+
|
11
|
+
=== Archive Installation
|
12
|
+
|
13
|
+
rake install
|
14
|
+
|
15
|
+
=== Gem Installation
|
16
|
+
|
17
|
+
gem install moro-repim
|
18
|
+
|
19
|
+
|
20
|
+
== Features/Problems
|
21
|
+
|
22
|
+
|
23
|
+
== Synopsis
|
24
|
+
|
25
|
+
|
26
|
+
== Copyright
|
27
|
+
|
28
|
+
Author:: MOROHASHI Kyosuke <moronatural@gmail.com>
|
29
|
+
Copyright:: Copyright (c) 2009 MOROHASHI Kyosuke
|
30
|
+
License:: MIT
|
data/Rakefile
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
require 'fileutils'
|
9
|
+
require 'spec/rake/spectask'
|
10
|
+
require 'lib/repim'
|
11
|
+
include FileUtils
|
12
|
+
|
13
|
+
use_rubyforge = false
|
14
|
+
NAME = "repim"
|
15
|
+
AUTHOR = "MOROHASHI Kyosuke"
|
16
|
+
EMAIL = "moronatural@gmail.com"
|
17
|
+
DESCRIPTION = "Relying Party in minutes."
|
18
|
+
|
19
|
+
if use_rubyforge
|
20
|
+
require 'rake/contrib/rubyforgepublisher'
|
21
|
+
require 'rake/contrib/sshpublisher'
|
22
|
+
RUBYFORGE_PROJECT = "repim"
|
23
|
+
HOMEPAGE = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
24
|
+
else
|
25
|
+
HOMEPAGE = "http://github.com/moro/#{NAME}/"
|
26
|
+
end
|
27
|
+
BIN_FILES = %w( )
|
28
|
+
|
29
|
+
VERS = Repim::Version
|
30
|
+
REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
|
31
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config']
|
32
|
+
RDOC_OPTS = [
|
33
|
+
'--title', "#{NAME} documentation",
|
34
|
+
"--charset", "utf-8",
|
35
|
+
"--opname", "index.html",
|
36
|
+
"--line-numbers",
|
37
|
+
"--main", "README.rdoc",
|
38
|
+
"--inline-source",
|
39
|
+
]
|
40
|
+
|
41
|
+
task :default => [:spec]
|
42
|
+
task :package => [:clean]
|
43
|
+
|
44
|
+
desc "Run all specs in spec directory"
|
45
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
46
|
+
t.spec_opts = %w[--colour --format progress --loadby --reverse]
|
47
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
48
|
+
end
|
49
|
+
|
50
|
+
namespace :spec do
|
51
|
+
desc "Run both plugin's and sample_app's"
|
52
|
+
task :all => %w[spec spec:sample_app]
|
53
|
+
|
54
|
+
desc "Run Sample app's tests"
|
55
|
+
task :sample_app do
|
56
|
+
begin
|
57
|
+
Dir.chdir("integration/sample-app") do
|
58
|
+
unless File.directory?("./vendor/plugins/open_id_authentication")
|
59
|
+
system(*%w[script/plugin install git://github.com/rails/open_id_authentication.git])
|
60
|
+
end
|
61
|
+
system("script/generate relying_party sessions")
|
62
|
+
system($0, "db:migrate")
|
63
|
+
system($0, "spec")
|
64
|
+
end
|
65
|
+
ensure
|
66
|
+
Rake::Task["spec:sample_app:clean"].invoke
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
namespace :sample_app do
|
71
|
+
desc "Clean Sample app's generated datas"
|
72
|
+
task :clean do
|
73
|
+
Dir.chdir("integration/sample-app") do
|
74
|
+
system("script/destroy relying_party sessions")
|
75
|
+
FileUtils.rm_f(["db/development.sqlite3", "db/test.sqlite3"])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
spec = Gem::Specification.new do |s|
|
82
|
+
s.name = NAME
|
83
|
+
s.version = VERS
|
84
|
+
s.platform = Gem::Platform::RUBY
|
85
|
+
s.has_rdoc = true
|
86
|
+
s.extra_rdoc_files = ["README.rdoc", "ChangeLog"]
|
87
|
+
s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
|
88
|
+
s.summary = DESCRIPTION
|
89
|
+
s.description = DESCRIPTION
|
90
|
+
s.author = AUTHOR
|
91
|
+
s.email = EMAIL
|
92
|
+
s.homepage = HOMEPAGE
|
93
|
+
s.executables = BIN_FILES
|
94
|
+
s.rubyforge_project = RUBYFORGE_PROJECT if use_rubyforge
|
95
|
+
s.bindir = "bin"
|
96
|
+
s.require_path = "lib"
|
97
|
+
s.test_files = Dir["test/*_test.rb"]
|
98
|
+
|
99
|
+
#s.add_dependency('activesupport', '>=1.3.1')
|
100
|
+
#s.required_ruby_version = '>= 1.8.2'
|
101
|
+
|
102
|
+
s.files = %w(README.rdoc ChangeLog Rakefile) +
|
103
|
+
Dir.glob("{bin,doc,test,lib,templates,generators,extras,website,script}/**/*") +
|
104
|
+
Dir.glob("ext/**/*.{h,c,rb}") +
|
105
|
+
Dir.glob("examples/**/*.rb") +
|
106
|
+
Dir.glob("tools/*.rb") +
|
107
|
+
Dir.glob("rails/*.rb")
|
108
|
+
|
109
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
110
|
+
end
|
111
|
+
|
112
|
+
Rake::GemPackageTask.new(spec) do |p|
|
113
|
+
p.need_tar = true
|
114
|
+
p.gem_spec = spec
|
115
|
+
end
|
116
|
+
|
117
|
+
task :install do
|
118
|
+
name = "#{NAME}-#{VERS}.gem"
|
119
|
+
sh %{rake package}
|
120
|
+
sh %{gem install pkg/#{name}}
|
121
|
+
end
|
122
|
+
|
123
|
+
task :uninstall => [:clean] do
|
124
|
+
sh %{gem uninstall #{NAME}}
|
125
|
+
end
|
126
|
+
|
127
|
+
desc 'Show information about the gem.'
|
128
|
+
task :debug_gem do
|
129
|
+
puts spec.to_ruby
|
130
|
+
end
|
131
|
+
|
132
|
+
desc 'Update gem spec'
|
133
|
+
task :gemspec do
|
134
|
+
open("#{NAME}.gemspec", 'w').write spec.to_ruby
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
Rake::RDocTask.new do |rdoc|
|
139
|
+
rdoc.rdoc_dir = 'html'
|
140
|
+
rdoc.options += RDOC_OPTS
|
141
|
+
rdoc.template = "resh"
|
142
|
+
#rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
143
|
+
if ENV['DOC_FILES']
|
144
|
+
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
|
145
|
+
else
|
146
|
+
rdoc.rdoc_files.include('README', 'ChangeLog')
|
147
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
148
|
+
rdoc.rdoc_files.include('ext/**/*.c')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
if use_rubyforge
|
153
|
+
desc "Publish to RubyForge"
|
154
|
+
task :rubyforge => [:rdoc, :package] do
|
155
|
+
require 'rubyforge'
|
156
|
+
Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, 'moro').upload
|
157
|
+
end
|
158
|
+
|
159
|
+
desc 'Package and upload the release to rubyforge.'
|
160
|
+
task :release => [:clean, :package] do |t|
|
161
|
+
v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
|
162
|
+
abort "Versions don't match #{v} vs #{VERS}" unless v == VERS
|
163
|
+
pkg = "pkg/#{NAME}-#{VERS}"
|
164
|
+
|
165
|
+
require 'rubyforge'
|
166
|
+
rf = RubyForge.new.configure
|
167
|
+
puts "Logging in"
|
168
|
+
rf.login
|
169
|
+
|
170
|
+
c = rf.userconfig
|
171
|
+
# c["release_notes"] = description if description
|
172
|
+
# c["release_changes"] = changes if changes
|
173
|
+
c["preformatted"] = true
|
174
|
+
|
175
|
+
files = [
|
176
|
+
"#{pkg}.tgz",
|
177
|
+
"#{pkg}.gem"
|
178
|
+
].compact
|
179
|
+
|
180
|
+
puts "Releasing #{NAME} v. #{VERS}"
|
181
|
+
rf.add_release RUBYFORGE_PROJECT, NAME, VERS, *files
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class RelyingPartyGenerator < Rails::Generator::NamedBase
|
2
|
+
def add_options!(opt)
|
3
|
+
opt.on("--skip-plugins-spec",
|
4
|
+
"Do'nt copy application_controller_spec.rb and #{plural_name}_controller_spec.rb, default is #{!using_rspec?}"){|v| options[:skip_sessions_spec] = true }
|
5
|
+
opt.on("--user-class=klass",
|
6
|
+
"Specify User class name defailt is [User]"){|v| opt[:user_klass] = "User" }
|
7
|
+
opt.on("--user-management=generation_type",
|
8
|
+
"'model' for generate (rspec_)model, 'singnup' for controller using Repim::Signup. default is 'signup'"){|v| options[:user_model_only] = (v == "model") }
|
9
|
+
opt.on("--openid-migration=migration_name",
|
10
|
+
"Specify openid migration name, default is 'open_id_authentication_tables'. If value is 'none' generate nothing.") do |v|
|
11
|
+
options[:openid_migration] = v
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def manifest
|
16
|
+
controller_file_name = plural_name + "_controller"
|
17
|
+
controller_class_name = controller_file_name.camelize
|
18
|
+
|
19
|
+
record do |m|
|
20
|
+
m.file "sessions_controller.rb", "app/controllers/#{controller_file_name}.rb"
|
21
|
+
assign_session_routing(singular_name, m)
|
22
|
+
|
23
|
+
m.directory "app/views/layouts"
|
24
|
+
m.file "views/layouts/sessions.html.erb", "app/views/layouts/#{plural_name}.html.erb"
|
25
|
+
|
26
|
+
m.directory "app/views/#{plural_name}"
|
27
|
+
m.file "views/sessions/new.html.erb", "app/views/#{plural_name}/new.html.erb"
|
28
|
+
|
29
|
+
%w[public/images/openid-login.gif public/stylesheets/repim.css].each do |asset|
|
30
|
+
m.directory File.dirname(asset)
|
31
|
+
m.file asset, asset
|
32
|
+
end
|
33
|
+
|
34
|
+
unless options[:skip_sessions_spec]
|
35
|
+
m.directory "spec/controllers"
|
36
|
+
m.file "spec/application_controller_spec.rb", "spec/controllers/application_controller_spec.rb"
|
37
|
+
|
38
|
+
m.file "spec/sessions_controller_spec.rb", "spec/controllers/#{controller_file_name}_spec.rb"
|
39
|
+
m.file "spec/sessions_routing_spec.rb", "spec/controllers/#{plural_name}_routing_spec.rb"
|
40
|
+
end
|
41
|
+
|
42
|
+
generate_user_management(m, !options[:skip_sessions_spec]) unless options[:user_model_only]
|
43
|
+
m.dependency(care_rspec("model"), [user_klass_name, "identity_url:string", @args].flatten.compact)
|
44
|
+
|
45
|
+
# FIXME very veriy dirty
|
46
|
+
# "sleep 3" is for changing timestamp of 'create_user' or 'open_id_authentication_tables'
|
47
|
+
if options[:command] == :create
|
48
|
+
m.gsub_file(app_controller, /(^\s*helper\s.*?$)/mi) do |ms|
|
49
|
+
sleep 3
|
50
|
+
"#{ms}\n include Repim::Application"
|
51
|
+
end
|
52
|
+
else
|
53
|
+
m.gsub_file(app_controller, /(^\s*include Repim::Application\s*$)/mi){|m| "" }
|
54
|
+
end
|
55
|
+
|
56
|
+
unless options[:openid_migration] == "none"
|
57
|
+
name = options[:openid_migration] || "open_id_authentication_tables"
|
58
|
+
m.dependency("open_id_authentication_tables", [name])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def app_controller
|
65
|
+
%w[application_controller application].
|
66
|
+
map{|f| "app/controllers/#{f}.rb" }.
|
67
|
+
detect{|c| File.exists?(File.expand_path(c, RAILS_ROOT)) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def care_rspec(base); using_rspec? ? "rspec_#{base}" : base end
|
71
|
+
|
72
|
+
def using_rspec?; File.directory?( File.expand_path("spec", RAILS_ROOT) ) end
|
73
|
+
|
74
|
+
def assign_session_routing(name, manifest)
|
75
|
+
sentinel = 'ActionController::Routing::Routes.draw do |map|'
|
76
|
+
|
77
|
+
logger.route "map.resource #{name}"
|
78
|
+
route = <<EOS
|
79
|
+
|
80
|
+
map.signin '/signin', :controller => 'sessions', :action => 'new'
|
81
|
+
map.signout '/signout', :controller => 'sessions', :action => 'destroy'
|
82
|
+
map.resource :session
|
83
|
+
EOS
|
84
|
+
|
85
|
+
unless options[:pretend]
|
86
|
+
if options[:command] == :create
|
87
|
+
manifest.gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
|
88
|
+
"#{match}#{route}"
|
89
|
+
end
|
90
|
+
else
|
91
|
+
manifest.gsub_file 'config/routes.rb', route, ''
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def user_klass_name
|
97
|
+
options[:user_klass] || "User"
|
98
|
+
end
|
99
|
+
def generate_user_management(m, with_spec = true)
|
100
|
+
users = user_klass_name.pluralize.underscore
|
101
|
+
user_controller_name = users + "_controller"
|
102
|
+
|
103
|
+
m.route_resources users.to_sym
|
104
|
+
m.file("users_controller.rb", "app/controllers/#{user_controller_name}.rb")
|
105
|
+
|
106
|
+
m.directory "app/views/#{users}"
|
107
|
+
m.template "views/users/new.html.erb", "app/views/#{users}/new.html.erb", :assigns => {:user => user_klass_name.underscore, :users => users}
|
108
|
+
|
109
|
+
if with_spec
|
110
|
+
m.file "spec/users_controller_spec.rb", "spec/controllers/#{user_controller_name}_spec.rb"
|
111
|
+
m.file "spec/users_routing_spec.rb", "spec/controllers/#{users}_routing_spec.rb"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
Binary file
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe ApplicationController do
|
4
|
+
before :all do
|
5
|
+
ApplicationController.user_klass = mock("User-Klass")
|
6
|
+
end
|
7
|
+
describe "#logged in" do
|
8
|
+
before do
|
9
|
+
session[:user_id] = 12345
|
10
|
+
ApplicationController.user_klass.should_receive(:find_by_id).with(12345).and_return(@user = mock("user"))
|
11
|
+
end
|
12
|
+
|
13
|
+
it{ controller.should be_signed_in }
|
14
|
+
it{ controller.current_user.should == @user }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe SessionsController do
|
4
|
+
before :all do
|
5
|
+
SessionsController.user_klass = mock("User-Klass")
|
6
|
+
end
|
7
|
+
|
8
|
+
#Delete this example and add some real ones
|
9
|
+
it "should use SessionsController" do
|
10
|
+
controller.should be_an_instance_of(SessionsController)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "get new should be success" do
|
14
|
+
get :new
|
15
|
+
response.should be_success
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "authentication success" do
|
19
|
+
before do
|
20
|
+
url = "---openid-url---"
|
21
|
+
|
22
|
+
@user = mock("user", :id => 12345)
|
23
|
+
SessionsController.user_klass.should_receive(:find_by_identity_url).with(url).and_return(@user)
|
24
|
+
|
25
|
+
result = mock("result")
|
26
|
+
result.should_receive(:successful?).and_return true
|
27
|
+
|
28
|
+
controller.should_receive(:root_path).and_return("/")
|
29
|
+
controller.should_receive(:authenticate_with_open_id).with(url, {}).and_yield(result,url, {})
|
30
|
+
|
31
|
+
post :create, :openid_url =>url
|
32
|
+
end
|
33
|
+
|
34
|
+
it{ response.should redirect_to("/") }
|
35
|
+
it{ session[:user_id].should == 12345 }
|
36
|
+
it{ controller.current_user.should == @user }
|
37
|
+
it{ controller.should be_signed_in }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "authentication success but user not found then render users/new" do
|
41
|
+
before do
|
42
|
+
url = "---openid-url---"
|
43
|
+
SessionsController.user_klass.should_receive(:find_by_identity_url).with(url).and_return(nil)
|
44
|
+
SessionsController.user_klass.should_receive(:new).with({}).and_return(@user = mock("user"))
|
45
|
+
|
46
|
+
result = mock("result")
|
47
|
+
result.should_receive(:successful?).and_return true
|
48
|
+
|
49
|
+
controller.should_receive(:authenticate_with_open_id).with(url, {}).and_yield(result,url, {})
|
50
|
+
|
51
|
+
post :create, :openid_url =>url
|
52
|
+
end
|
53
|
+
|
54
|
+
it{ response.should render_template("users/new") }
|
55
|
+
it{ controller.current_user.should be_nil }
|
56
|
+
it{ controller.should_not be_signed_in }
|
57
|
+
it{ assigns[:user].should == @user }
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "authentication failed" do
|
61
|
+
before do
|
62
|
+
url = "---openid-url---"
|
63
|
+
|
64
|
+
result = mock("result")
|
65
|
+
result.should_receive(:successful?).and_return false
|
66
|
+
|
67
|
+
controller.should_receive(:authenticate_with_open_id).with(url, {}).and_yield(result,url, {})
|
68
|
+
|
69
|
+
post :create, :openid_url =>url
|
70
|
+
end
|
71
|
+
|
72
|
+
it{ response.should render_template("sessions/new") }
|
73
|
+
it{ assigns[:user].should be_nil }
|
74
|
+
it{ controller.current_user.should be_nil }
|
75
|
+
it{ session[:user_id].should be_nil }
|
76
|
+
it{ flash[:error].should_not be_blank }
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe SessionsController do
|
4
|
+
describe "route generation" do
|
5
|
+
it "should map #new -> /signin" do
|
6
|
+
route_for(:controller => "sessions", :action => "new").should == "/signin"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should map #destroy -> /signout" do
|
10
|
+
route_for(:controller => "sessions", :action => "destroy").should == "/signout"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should map #show" do
|
14
|
+
route_for(:controller => "sessions", :action => "show").should == "/session"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should map #edit" do
|
18
|
+
route_for(:controller => "sessions", :action => "edit").should == "/session/edit"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should map #update" do
|
22
|
+
route_for(:controller => "sessions", :action => "update").should == "/session"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "route recognition" do
|
27
|
+
it "should generate params for #new" do
|
28
|
+
params_from(:get, "/signin").should == {:controller => "sessions", :action => "new"}
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should generate params for #new" do
|
32
|
+
params_from(:get, "/session/new").should == {:controller => "sessions", :action => "new"}
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should generate params for #create" do
|
36
|
+
params_from(:post, "/session").should == {:controller => "sessions", :action => "create"}
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should generate params for #show (JS)" do
|
40
|
+
params_from(:get, "/session.js").should == {:controller => "sessions", :action => "show", :format => "js"}
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should generate params for #destroy" do
|
44
|
+
params_from(:get, "/signout").should == {:controller => "sessions", :action => "destroy"}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should generate params for #destroy" do
|
48
|
+
params_from(:delete, "/session").should == {:controller => "sessions", :action => "destroy"}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe UsersController do
|
4
|
+
def mock_user(stubs={})
|
5
|
+
@mock_user ||= mock_model(User, stubs)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "responding to GET index" do
|
9
|
+
before do
|
10
|
+
controller.stub!(:authenticate).and_return true
|
11
|
+
end
|
12
|
+
it "should expose all users as @users" do
|
13
|
+
User.should_receive(:find).with(:all).and_return([mock_user])
|
14
|
+
get :index
|
15
|
+
assigns[:users].should == [mock_user]
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "with mime type of xml" do
|
19
|
+
it "should render all users as xml" do
|
20
|
+
request.env["HTTP_ACCEPT"] = "application/xml"
|
21
|
+
User.should_receive(:find).with(:all).and_return(users = mock("Array of Users"))
|
22
|
+
users.should_receive(:to_xml).and_return("generated XML")
|
23
|
+
get :index
|
24
|
+
response.body.should == "generated XML"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "responding to GET show" do
|
30
|
+
before do
|
31
|
+
controller.stub!(:authenticate).and_return true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should expose the requested user as @user" do
|
35
|
+
User.should_receive(:find).with("37").and_return(mock_user)
|
36
|
+
get :show, :id => "37"
|
37
|
+
assigns[:user].should equal(mock_user)
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "with mime type of xml" do
|
41
|
+
it "should render the requested user as xml" do
|
42
|
+
request.env["HTTP_ACCEPT"] = "application/xml"
|
43
|
+
User.should_receive(:find).with("37").and_return(mock_user)
|
44
|
+
mock_user.should_receive(:to_xml).and_return("generated XML")
|
45
|
+
get :show, :id => "37"
|
46
|
+
response.body.should == "generated XML"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "responding to POST create" do
|
52
|
+
describe "with valid params" do
|
53
|
+
before do
|
54
|
+
User.should_receive(:new).with({'these' => 'params'}).and_return(mock_user(:save => true))
|
55
|
+
|
56
|
+
@identity_url = session[:identity_url] = "http://moro.openid.example.com/"
|
57
|
+
mock_user.should_receive(:identity_url=).with(@identity_url)
|
58
|
+
|
59
|
+
post :create, :user => {:these => 'params'}
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should expose a newly created user as @user" do
|
63
|
+
assigns(:user).should equal(mock_user)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "session[:identity_url] should be removed" do
|
67
|
+
session[:identity_url].should be_blank
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should redirect to the created user" do
|
71
|
+
response.should redirect_to(user_url(mock_user))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "with invalid params" do
|
76
|
+
before do
|
77
|
+
User.stub!(:new).with({'these' => 'params'}).and_return(mock_user(:save => false))
|
78
|
+
|
79
|
+
@identity_url = session[:identity_url] = "http://moro.openid.example.com/"
|
80
|
+
mock_user.should_receive(:identity_url=).with(@identity_url)
|
81
|
+
|
82
|
+
post :create, :user => {:these => 'params'}
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should expose a newly created but unsaved user as @user" do
|
86
|
+
assigns(:user).should equal(mock_user)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should re-render the 'new' template" do
|
90
|
+
response.should render_template('new')
|
91
|
+
end
|
92
|
+
|
93
|
+
it "session[:identity_url] should == original" do
|
94
|
+
session[:identity_url].should == @identity_url
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe UsersController do
|
4
|
+
describe "route generation" do
|
5
|
+
it "should map #index" do
|
6
|
+
route_for(:controller => "users", :action => "index").should == "/users"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should map #new" do
|
10
|
+
route_for(:controller => "users", :action => "new").should == "/users/new"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should map #show" do
|
14
|
+
route_for(:controller => "users", :action => "show", :id => 1).should == "/users/1"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should map #edit" do
|
18
|
+
route_for(:controller => "users", :action => "edit", :id => 1).should == "/users/1/edit"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should map #update" do
|
22
|
+
route_for(:controller => "users", :action => "update", :id => 1).should == "/users/1"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should map #destroy" do
|
26
|
+
route_for(:controller => "users", :action => "destroy", :id => 1).should == "/users/1"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "route recognition" do
|
31
|
+
it "should generate params for #index" do
|
32
|
+
params_from(:get, "/users").should == {:controller => "users", :action => "index"}
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should generate params for #new" do
|
36
|
+
params_from(:get, "/users/new").should == {:controller => "users", :action => "new"}
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should generate params for #create" do
|
40
|
+
params_from(:post, "/users").should == {:controller => "users", :action => "create"}
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should generate params for #show" do
|
44
|
+
params_from(:get, "/users/1").should == {:controller => "users", :action => "show", :id => "1"}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should generate params for #edit" do
|
48
|
+
params_from(:get, "/users/1/edit").should == {:controller => "users", :action => "edit", :id => "1"}
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should generate params for #update" do
|
52
|
+
params_from(:put, "/users/1").should == {:controller => "users", :action => "update", :id => "1"}
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should generate params for #destroy" do
|
56
|
+
params_from(:delete, "/users/1").should == {:controller => "users", :action => "destroy", :id => "1"}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class UsersController < ApplicationController
|
2
|
+
include Repim::Signup
|
3
|
+
|
4
|
+
def index
|
5
|
+
@users = User.find(:all)
|
6
|
+
|
7
|
+
respond_to do |format|
|
8
|
+
format.html
|
9
|
+
format.xml { render :xml => @users }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def show
|
14
|
+
@user = User.find(params[:id])
|
15
|
+
|
16
|
+
respond_to do |format|
|
17
|
+
format.html
|
18
|
+
format.xml { render :xml => @user }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<%= stylesheet_link_tag "repim" %>
|
4
|
+
<%= javascript_include_tag :defaults %>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<div id="header">
|
8
|
+
<% if signed_in? -%>
|
9
|
+
<span class="current-user"> Logged in as <%= current_user.identity_url %> </span>
|
10
|
+
<% else -%>
|
11
|
+
<span class="sign-in"><%= link_to "Sign in", new_session_path %></span>
|
12
|
+
<% end -%>
|
13
|
+
</div>
|
14
|
+
<div id="content">
|
15
|
+
<%= yield %>
|
16
|
+
</div>
|
17
|
+
</body>
|
18
|
+
</html>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<h1>Welcome</h1>
|
2
|
+
|
3
|
+
<div id="login-or-signup">
|
4
|
+
<p> Please login or signup using OpenID.</p>
|
5
|
+
|
6
|
+
<% form_tag session_path do -%>
|
7
|
+
<label for="openid_url">OpenID URL</label>
|
8
|
+
<%= text_field_tag "openid_url", params[:openid_url] %>
|
9
|
+
|
10
|
+
<%= submit_tag "Login or Signup" %>
|
11
|
+
<% end %>
|
12
|
+
</div>
|
13
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<h1>Sign up</h1>
|
2
|
+
|
3
|
+
<%% form_for(@<%= user %>) do |f| %>
|
4
|
+
<%%= f.error_messages %>
|
5
|
+
|
6
|
+
<table>
|
7
|
+
<% for attribute in attributes -%>
|
8
|
+
<tr>
|
9
|
+
<th> <%%= f.label :<%= attribute.name %> %></th>
|
10
|
+
<td><%%= f.<%= attribute.field_type %> :<%= attribute.name %> %></td>
|
11
|
+
</tr>
|
12
|
+
<% end -%>
|
13
|
+
<tr>
|
14
|
+
<th>OpenID URL</th>
|
15
|
+
<td><%%=h session[:identity_url] %></td>
|
16
|
+
</tr>
|
17
|
+
</table>
|
18
|
+
<p>
|
19
|
+
<%%= f.submit 'Create' %>
|
20
|
+
</p>
|
21
|
+
<%% end %>
|
22
|
+
|
23
|
+
<%%= link_to 'Back', <%= users %>_path %>
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Repim
|
2
|
+
module Application
|
3
|
+
def self.included(base)
|
4
|
+
base.cattr_accessor :user_klass
|
5
|
+
base.cattr_accessor :login_template
|
6
|
+
base.user_klass = (User rescue nil) # assign nil when LoadError and/or ConstMissing
|
7
|
+
base.login_template = "sessions/new"
|
8
|
+
|
9
|
+
[:current_user, :signed_in?, :logged_in?].each do |method|
|
10
|
+
base.helper_method method
|
11
|
+
base.hide_action method
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def signed_in?; !!current_user ; end
|
16
|
+
alias logged_in? signed_in?
|
17
|
+
|
18
|
+
def current_user
|
19
|
+
return nil if @__current_user__ == false
|
20
|
+
return @__current_user__ if @__current_user__
|
21
|
+
@__current_user__ ||= (user_from_session || false)
|
22
|
+
current_user # call again
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def authenticate
|
27
|
+
signed_in? || access_denied("Login required.")
|
28
|
+
end
|
29
|
+
alias login_required authenticate
|
30
|
+
|
31
|
+
def access_denied(message = nil)
|
32
|
+
store_location
|
33
|
+
flash[:error] = message if message
|
34
|
+
render :template => login_template, :status => :unauthorized
|
35
|
+
end
|
36
|
+
|
37
|
+
def store_location
|
38
|
+
session[:return_to] = request.request_uri if request.get?
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_user=(user)
|
42
|
+
@__current_user__ = user
|
43
|
+
session[:user_id] = user.id
|
44
|
+
end
|
45
|
+
|
46
|
+
def user_from_session
|
47
|
+
session[:user_id] && user_klass.find_by_id(session[:user_id])
|
48
|
+
end
|
49
|
+
|
50
|
+
def redirect_back_or(default)
|
51
|
+
redirect_to(session[:return_to] || default)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module Repim
|
4
|
+
class AxAttributeAdapter
|
5
|
+
attr_reader :rule, :necessity
|
6
|
+
|
7
|
+
# TODO refactor
|
8
|
+
def initialize(prefixes, propaties)
|
9
|
+
@rule = {}
|
10
|
+
@necessity = :optional
|
11
|
+
propaties.each do |model_attr, property|
|
12
|
+
@rule[model_attr] = prefixes.map{|px| px + property }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def keys
|
17
|
+
rule.values.flatten
|
18
|
+
end
|
19
|
+
|
20
|
+
def required!
|
21
|
+
@necessity = :required
|
22
|
+
end
|
23
|
+
|
24
|
+
def adapt(fetched)
|
25
|
+
returning({}) do |res|
|
26
|
+
rule.each do |k, vs|
|
27
|
+
fetched.each{|fk, (fv,_)| res[k] = fv if !fv.blank? && vs.include?(fk) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'repim/ax_attributes_adapter'
|
2
|
+
|
3
|
+
module Repim
|
4
|
+
module RelyingParty
|
5
|
+
def self.included(base)
|
6
|
+
base.cattr_accessor :attribute_adapter
|
7
|
+
base.cattr_accessor :signup_template
|
8
|
+
|
9
|
+
base.signup_template = "users/new"
|
10
|
+
|
11
|
+
base.extend(ClassMethods)
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def use_attribute_exchange(prefixes, propaties)
|
16
|
+
self.attribute_adapter = AxAttributeAdapter.new(prefixes, propaties)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# render new.rhtml
|
21
|
+
def new
|
22
|
+
end
|
23
|
+
|
24
|
+
def create
|
25
|
+
options = {}
|
26
|
+
options[attribute_adapter.necessity] = attribute_adapter.keys if attribute_adapter
|
27
|
+
|
28
|
+
begin
|
29
|
+
authenticate_with_open_id(params[:openid_url], options) do |result, identity_url, personal_data|
|
30
|
+
if result.successful?
|
31
|
+
authenticate_success(identity_url, personal_data)
|
32
|
+
else
|
33
|
+
authenticate_failure(params.merge(:openid_url=>identity_url))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
rescue OpenID::OpenIDError => why
|
37
|
+
logger.debug{ [why.message, why.backtrace].flatten.join("\n\t") }
|
38
|
+
authenticate_failure(params)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def destroy
|
43
|
+
session[:user_id] = nil
|
44
|
+
reset_session
|
45
|
+
flash[:notice] = "You have been logged out."
|
46
|
+
|
47
|
+
redirect_back_or(after_logout_path)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def authenticate_success(identity_url, personal_data = {})
|
52
|
+
if user = user_klass.find_by_identity_url(identity_url)
|
53
|
+
login_successfully(user, personal_data)
|
54
|
+
redirect_back_or(after_login_path)
|
55
|
+
else
|
56
|
+
signup(identity_url, personal_data)
|
57
|
+
render(:template => signup_template)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def login_successfully(user, personal_data)
|
62
|
+
reset_session
|
63
|
+
self.current_user = user
|
64
|
+
flash[:notice] ||= "Logged in successfully"
|
65
|
+
end
|
66
|
+
|
67
|
+
def signup(identity_url, ax = {})
|
68
|
+
session[:identity_url] = identity_url
|
69
|
+
@user = user_klass.new( attribute_adapter ? attribute_adapter.adapt(ax) : {} )
|
70
|
+
end
|
71
|
+
|
72
|
+
# log login faulure. and re-render sessions/new
|
73
|
+
def authenticate_failure(assigns = params)
|
74
|
+
flash[:error] = "Couldn't log you in as '#{assigns[:openid_url] || assigns["openid.claimed_id"]}'"
|
75
|
+
logger.warn "Failed login for '#{assigns[:openid_url]}' from #{request.remote_ip} at #{Time.now.utc}"
|
76
|
+
|
77
|
+
@openid_url = assigns[:openid_url]
|
78
|
+
|
79
|
+
render :action => 'new'
|
80
|
+
end
|
81
|
+
|
82
|
+
def after_login_path; root_path ; end
|
83
|
+
def after_logout_path; login_path ; end
|
84
|
+
|
85
|
+
def method_missing(m, *args, &b)
|
86
|
+
return [request.protocol, request.host_with_port, "/"].join if m.to_sym == :root_url
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/repim/signup.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Repim
|
2
|
+
module Signup
|
3
|
+
def self.included(base)
|
4
|
+
base.before_filter :authenticate, :except => [:create]
|
5
|
+
end
|
6
|
+
|
7
|
+
def create
|
8
|
+
@user = User.new(params[:user])
|
9
|
+
@user.identity_url = session[:identity_url]
|
10
|
+
|
11
|
+
respond_to do |format|
|
12
|
+
if @user.save
|
13
|
+
flash[:notice] = 'User was successfully created.'
|
14
|
+
reset_session
|
15
|
+
self.current_user = @user
|
16
|
+
format.html { redirect_to(after_create_url) }
|
17
|
+
else
|
18
|
+
format.html { render :action => "new" }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def after_create_url
|
25
|
+
current_user
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/repim.rb
ADDED
data/rails/init.rb
ADDED
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: moro-repim
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- MOROHASHI Kyosuke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-10 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Relying Party in minutes.
|
17
|
+
email: moronatural@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
- ChangeLog
|
25
|
+
files:
|
26
|
+
- README.rdoc
|
27
|
+
- ChangeLog
|
28
|
+
- Rakefile
|
29
|
+
- lib/repim
|
30
|
+
- lib/repim/application.rb
|
31
|
+
- lib/repim/ax_attributes_adapter.rb
|
32
|
+
- lib/repim/relying_party.rb
|
33
|
+
- lib/repim/signup.rb
|
34
|
+
- lib/repim.rb
|
35
|
+
- generators/relying_party
|
36
|
+
- generators/relying_party/relying_party_generator.rb
|
37
|
+
- generators/relying_party/templates
|
38
|
+
- generators/relying_party/templates/public
|
39
|
+
- generators/relying_party/templates/public/images
|
40
|
+
- generators/relying_party/templates/public/images/openid-login.gif
|
41
|
+
- generators/relying_party/templates/public/stylesheets
|
42
|
+
- generators/relying_party/templates/public/stylesheets/repim.css
|
43
|
+
- generators/relying_party/templates/sessions_controller.rb
|
44
|
+
- generators/relying_party/templates/spec
|
45
|
+
- generators/relying_party/templates/spec/application_controller_spec.rb
|
46
|
+
- generators/relying_party/templates/spec/sessions_controller_spec.rb
|
47
|
+
- generators/relying_party/templates/spec/sessions_routing_spec.rb
|
48
|
+
- generators/relying_party/templates/spec/users_controller_spec.rb
|
49
|
+
- generators/relying_party/templates/spec/users_routing_spec.rb
|
50
|
+
- generators/relying_party/templates/users_controller.rb
|
51
|
+
- generators/relying_party/templates/views
|
52
|
+
- generators/relying_party/templates/views/layouts
|
53
|
+
- generators/relying_party/templates/views/layouts/sessions.html.erb
|
54
|
+
- generators/relying_party/templates/views/sessions
|
55
|
+
- generators/relying_party/templates/views/sessions/new.html.erb
|
56
|
+
- generators/relying_party/templates/views/users
|
57
|
+
- generators/relying_party/templates/views/users/new.html.erb
|
58
|
+
- rails/init.rb
|
59
|
+
has_rdoc: false
|
60
|
+
homepage: http://github.com/moro/repim/
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --title
|
64
|
+
- repim documentation
|
65
|
+
- --charset
|
66
|
+
- utf-8
|
67
|
+
- --opname
|
68
|
+
- index.html
|
69
|
+
- --line-numbers
|
70
|
+
- --main
|
71
|
+
- README.rdoc
|
72
|
+
- --inline-source
|
73
|
+
- --exclude
|
74
|
+
- ^(examples|extras)/
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
version:
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: "0"
|
88
|
+
version:
|
89
|
+
requirements: []
|
90
|
+
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 1.2.0
|
93
|
+
signing_key:
|
94
|
+
specification_version: 2
|
95
|
+
summary: Relying Party in minutes.
|
96
|
+
test_files: []
|
97
|
+
|