warden_oauth_provider 1.0.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.
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe "OAuth all steps" do
4
+
5
+ context "Success" do
6
+
7
+ before(:all) do
8
+ @client_application = Factory.create(:client_application)
9
+ @user = Factory(:user)
10
+ end
11
+
12
+ it "should succeed all oauth steps" do
13
+
14
+ # Step 1 - Request token
15
+ auth_str_step1 = oauth_header({
16
+ :realm => "MoneyBird",
17
+ :oauth_consumer_key => @client_application.key,
18
+ :oauth_signature_method => "PLAINTEXT",
19
+ :oauth_timestamp => Time.now.to_i+1,
20
+ :oauth_nonce => Time.now.to_f+1,
21
+ :oauth_callback => "oob",
22
+ :oauth_signature => @client_application.secret + "%26"
23
+ })
24
+ env_step1 = env_with_params("/oauth/request_token", {}, {
25
+ "HTTP_AUTHORIZATION" => auth_str_step1
26
+ })
27
+ response = setup_rack.call(env_step1)
28
+ response.first.should == 200
29
+ oauth_response = Hash[*response.last.first.split("&").collect { |v| v.split("=") }.flatten]
30
+ oauth_request_token = oauth_response["oauth_token"]
31
+ oauth_request_token_secret = oauth_response["oauth_token_secret"]
32
+
33
+ # Step 2 - Authorize
34
+ req = WardenOauthProvider::Token::Request.find_by_token(oauth_request_token)
35
+ env_step2 = env_with_params("/oauth/authorize", {:oauth_token => oauth_request_token, :username => "John"}, {})
36
+ response = setup_rack.call(env_step2)
37
+ response.first.should == 302
38
+ location = URI.parse(response[1]["Location"])
39
+ oauth_response = Hash[*location.query.split("&").collect { |v| v.split("=") }.flatten]
40
+ oauth_verifier = oauth_response["oauth_verifier"]
41
+
42
+ # Step 3 - Access token
43
+ auth_str_step3 = oauth_header({
44
+ :realm => "MoneyBird",
45
+ :oauth_consumer_key => @client_application.key,
46
+ :oauth_token => oauth_request_token,
47
+ :oauth_signature_method => "PLAINTEXT",
48
+ :oauth_timestamp => Time.now.to_i+2,
49
+ :oauth_nonce => Time.now.to_f+2,
50
+ :oauth_verifier => oauth_verifier,
51
+ :oauth_signature => @client_application.secret + "%26" + oauth_request_token_secret
52
+ })
53
+ env_step3 = env_with_params("/oauth/access_token", {}, {
54
+ "HTTP_AUTHORIZATION" => auth_str_step3
55
+ })
56
+ response = setup_rack.call(env_step3)
57
+ response.first.should == 200
58
+ oauth_response = Hash[*response.last.first.split("&").collect { |v| v.split("=") }.flatten]
59
+ oauth_access_token = oauth_response["oauth_token"]
60
+ oauth_access_token_secret = oauth_response["oauth_token_secret"]
61
+
62
+ # Step 4 - App request with access token
63
+ auth_str_step4 = oauth_header({
64
+ :realm => "MoneyBird",
65
+ :oauth_consumer_key => @client_application.key,
66
+ :oauth_token => oauth_access_token,
67
+ :oauth_signature_method => "PLAINTEXT",
68
+ :oauth_timestamp => Time.now.to_i+3,
69
+ :oauth_nonce => Time.now.to_f+3,
70
+ :oauth_signature => @client_application.secret + "%26" + oauth_access_token_secret
71
+ })
72
+ env_step4 = env_with_params("/invoices", {}, {
73
+ "HTTP_AUTHORIZATION" => auth_str_step4
74
+ })
75
+ response = setup_rack.call(env_step4)
76
+ response.first.should == 200
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Authorize" do
4
+
5
+ context "Success" do
6
+
7
+ before(:all) do
8
+ @request_token = Factory.create(:request_token, :client_application => Factory.create(:client_application))
9
+ env = env_with_params("/oauth/authorize", {:oauth_token => @request_token.token, :username => "John"}, {})
10
+ @response = setup_rack.call(env)
11
+ @location = URI.parse(@response[1]["Location"])
12
+ @oauth_response = Hash[*@location.query.split("&").collect { |v| v.split("=") }.flatten]
13
+ @response.first.should == 302
14
+ end
15
+
16
+ it "should have an oauth token" do
17
+ @oauth_response.keys.should include("oauth_token")
18
+ @oauth_response["oauth_token"].should == @request_token.token
19
+ end
20
+
21
+ it "should have an oauth verifier" do
22
+ @oauth_response.keys.should include("oauth_verifier")
23
+ @oauth_response["oauth_verifier"].should_not be_nil
24
+ end
25
+
26
+ it "should have stored the oauth verifier in the database" do
27
+ WardenOauthProvider::Token::Request.where(:token => @oauth_response["oauth_token"], :verifier => @oauth_response["oauth_verifier"]).count.should == 1
28
+ end
29
+
30
+ end
31
+
32
+ context "Failure" do
33
+ it "should response with a 401 if the token is invalidated" do
34
+ @request_token = Factory.create(:request_token, :client_application => Factory.create(:client_application))
35
+ @request_token.invalidate!
36
+
37
+ env = env_with_params("/oauth/authorize", {:oauth_token => @request_token.token}, {})
38
+ @response = setup_rack.call(env)
39
+ @response.first.should == 401
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe WardenOauthProvider::ClientApplication do
4
+
5
+ it "should be valid with valid attributes" do
6
+ @application = WardenOauthProvider::ClientApplication.create(:name => "Test application", :url => "http://testapp.com")
7
+ @application.should be_valid
8
+ end
9
+
10
+ it "should be invalid with invalid attributes" do
11
+ @application = WardenOauthProvider::ClientApplication.new
12
+ @application.valid?
13
+ @application.errors[:name].should_not be_empty
14
+ @application.errors[:url].should_not be_empty
15
+ end
16
+
17
+ it "should have key and secret" do
18
+ @application = WardenOauthProvider::ClientApplication.create(:name => "Test application", :url => "http://testapp.com")
19
+ @application.key.should_not be_nil
20
+ @application.secret.should_not be_nil
21
+ end
22
+
23
+ ["http://valid.com",
24
+ "http://valid.com/path"].each do |url|
25
+ it "should allow #{url} as a valid url" do
26
+ @application = WardenOauthProvider::ClientApplication.new(:url => url)
27
+ @application.valid?
28
+ @application.errors[:url].should be_empty
29
+ end
30
+ end
31
+
32
+ ["ftp://invalid.com",
33
+ "http:://invalid.com"].each do |url|
34
+ it "should not allow #{url} as a valid url" do
35
+ @application = WardenOauthProvider::ClientApplication.new(:url => url)
36
+ @application.valid?
37
+ @application.errors[:url].should_not be_empty
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,16 @@
1
+ Factory.define(:client_application, :class => WardenOauthProvider::ClientApplication) do |f|
2
+ f.name "Example client application"
3
+ f.url "http://www.example.com"
4
+ f.support_url "http://www.example.com/support"
5
+ f.callback_url "http://www.example.com/callback"
6
+ end
7
+
8
+ Factory.define(:request_token, :class => WardenOauthProvider::Token::Request) do |f|
9
+ end
10
+
11
+ Factory.define(:access_token, :class => WardenOauthProvider::Token::Access) do |f|
12
+ end
13
+
14
+ Factory.define(:user) do |f|
15
+ f.name "John"
16
+ end
@@ -0,0 +1,87 @@
1
+ module RequestHelper
2
+
3
+ Warden::Manager.serialize_into_session do |user|
4
+ user.id
5
+ end
6
+
7
+ Warden::Manager.serialize_from_session do |id|
8
+ User.find(id)
9
+ end
10
+
11
+ def env_with_params(path, params = {}, env = {})
12
+ method = params.delete(:method) || "GET"
13
+ env = { 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => "#{method}" }.merge(env)
14
+ Rack::MockRequest.env_for("#{path}?#{Rack::Utils.build_query(params)}", env)
15
+ end
16
+
17
+ def oauth_header(params)
18
+ "OAuth #{params.collect { |k,v| "#{k}=\"#{v}\""}.join(", ") }"
19
+ end
20
+
21
+ def setup_rack(app = nil, opts = {})
22
+ app ||= default_app
23
+
24
+ # Strategy used for authenticating the user to the app without oauth
25
+ # Required for authorize call to the app
26
+ Warden::Strategies.add(:success) do
27
+ def valid?
28
+ !params["username"].nil?
29
+ end
30
+
31
+ def authenticate!
32
+ if u = User.where(:name => params["username"]).first
33
+ success!(u)
34
+ else
35
+ fail!("User unknown")
36
+ end
37
+ end
38
+ end
39
+
40
+ opts[:failure_app] ||= failure_app
41
+ opts[:default_strategies] ||= [:oauth_provider, :success]
42
+ opts[:oauth_request_token_path] ||= "/oauth/request_token"
43
+ opts[:oauth_access_token_path] ||= "/oauth/access_token"
44
+
45
+ Rack::Builder.new do
46
+ use opts[:session] || RequestHelper::Session
47
+ use Warden::Manager, opts
48
+ run app
49
+ end
50
+ end
51
+
52
+ def default_app
53
+ lambda do |env|
54
+ env['warden'].authenticate!
55
+ request = Rack::Request.new(env)
56
+ if request.path =~ /^\/oauth\/authorize/
57
+ if env['warden'].authenticate?(:oauth_token, :scope => :oauth_token)
58
+ [302, {"Location" => env['oauth.redirect_url']}, []]
59
+ else
60
+ [401, {"Content-Type" => "text/plain"}, ["Token invalid"]]
61
+ end
62
+ else
63
+ [200, {"Content-Type" => "text/plain"}, ["Very secret resource!"]]
64
+ end
65
+ end
66
+ end
67
+
68
+ def failure_app
69
+ lambda do |env|
70
+ [401, {"Content-Type" => "text/plain"}, ["You Fail! #{env['warden'].message}"]]
71
+ end
72
+ end
73
+
74
+
75
+ class Session
76
+ attr_accessor :app
77
+ def initialize(app,configs = {})
78
+ @app = app
79
+ end
80
+
81
+ def call(e)
82
+ e['rack.session'] ||= {}
83
+ @app.call(e)
84
+ end
85
+ end # session
86
+
87
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe WardenOauthProvider::Nonce do
4
+ before(:each) do
5
+ @oauth_nonce = WardenOauthProvider::Nonce.remember(Time.now.to_f, Time.now.to_i)
6
+ end
7
+
8
+ it "should be valid" do
9
+ @oauth_nonce.should be_valid
10
+ end
11
+
12
+ it "should not have errors" do
13
+ @oauth_nonce.errors.full_messages.should == []
14
+ end
15
+
16
+ it "should not be a new record" do
17
+ @oauth_nonce.should_not be_new_record
18
+ end
19
+
20
+ it "should not allow a second one with the same values" do
21
+ WardenOauthProvider::Nonce.remember(@oauth_nonce.nonce, @oauth_nonce.timestamp).should == false
22
+ end
23
+ end
@@ -0,0 +1,161 @@
1
+ require 'spec_helper'
2
+
3
+ describe "OAuth request" do
4
+
5
+ context "Success" do
6
+
7
+ before(:all) do
8
+ @user = Factory(:user)
9
+ @client_application = Factory.create(:client_application)
10
+ @access_token = Factory.create(:access_token, :user => @user, :client_application => @client_application)
11
+ end
12
+
13
+ it "should allow to access very secret resources" do
14
+ auth_str = oauth_header({
15
+ :realm => "MoneyBird",
16
+ :oauth_consumer_key => @client_application.key,
17
+ :oauth_token => @access_token.token,
18
+ :oauth_signature_method => "PLAINTEXT",
19
+ :oauth_timestamp => Time.now.to_i,
20
+ :oauth_nonce => Time.now.to_f,
21
+ :oauth_signature => @client_application.secret + "%26" + @access_token.secret
22
+ })
23
+
24
+ env = env_with_params("/invoices", {}, {
25
+ "HTTP_AUTHORIZATION" => auth_str
26
+ })
27
+ @response = setup_rack.call(env)
28
+ @response.first.should == 200
29
+ end
30
+
31
+ end
32
+
33
+ context "Success (GET)" do
34
+
35
+ before(:all) do
36
+ @user = Factory(:user)
37
+ @client_application = Factory.create(:client_application)
38
+ @access_token = Factory.create(:access_token, :user => @user, :client_application => @client_application)
39
+ end
40
+
41
+ it "should allow to access very secret resources" do
42
+ auth_params = {
43
+ :realm => "MoneyBird",
44
+ :oauth_consumer_key => @client_application.key,
45
+ :oauth_token => @access_token.token,
46
+ :oauth_signature_method => "PLAINTEXT",
47
+ :oauth_timestamp => Time.now.to_i,
48
+ :oauth_nonce => Time.now.to_f,
49
+ :oauth_signature => @client_application.secret + "&" + @access_token.secret
50
+ }
51
+
52
+ env = env_with_params("/invoices", auth_params)
53
+ @response = setup_rack.call(env)
54
+ @response.first.should == 200
55
+ end
56
+
57
+ end
58
+
59
+ context "Failure" do
60
+
61
+ before(:all) do
62
+ @user = Factory(:user)
63
+ @client_application = Factory.create(:client_application)
64
+ @access_token = Factory.create(:access_token, :user => @user, :client_application => @client_application)
65
+ end
66
+
67
+ it "should not allow to access very secret resources if the second request contains the same nonce" do
68
+ auth_str = oauth_header({
69
+ :realm => "MoneyBird",
70
+ :oauth_consumer_key => @client_application.key,
71
+ :oauth_token => @access_token.token,
72
+ :oauth_signature_method => "PLAINTEXT",
73
+ :oauth_timestamp => Time.now.to_i,
74
+ :oauth_nonce => Time.now.to_f,
75
+ :oauth_signature => @client_application.secret + "%26" + @access_token.secret
76
+ })
77
+ env1 = env_with_params("/invoices", {}, {
78
+ "HTTP_AUTHORIZATION" => auth_str
79
+ })
80
+ env2 = env_with_params("/invoices", {}, {
81
+ "HTTP_AUTHORIZATION" => auth_str
82
+ })
83
+
84
+ @response1 = setup_rack.call(env1)
85
+ @response2 = setup_rack.call(env2)
86
+ @response2.first.should == 401
87
+ end
88
+
89
+ it "should not allow to access very secret resources with invalid consumer key" do
90
+ auth_str = oauth_header({
91
+ :realm => "MoneyBird",
92
+ :oauth_consumer_key => @client_application.key + "invalid",
93
+ :oauth_token => @access_token.token,
94
+ :oauth_signature_method => "PLAINTEXT",
95
+ :oauth_timestamp => Time.now.to_i,
96
+ :oauth_nonce => Time.now.to_f,
97
+ :oauth_signature => @client_application.secret + "%26" + @access_token.secret
98
+ })
99
+
100
+ env = env_with_params("/invoices", {}, {
101
+ "HTTP_AUTHORIZATION" => auth_str
102
+ })
103
+ @response = setup_rack.call(env)
104
+ @response.first.should == 401
105
+ end
106
+
107
+ it "should not allow to access very secret resources with invalid token" do
108
+ auth_str = oauth_header({
109
+ :realm => "MoneyBird",
110
+ :oauth_consumer_key => @client_application.key,
111
+ :oauth_token => @access_token.token + "invalid",
112
+ :oauth_signature_method => "PLAINTEXT",
113
+ :oauth_timestamp => Time.now.to_i,
114
+ :oauth_nonce => Time.now.to_f,
115
+ :oauth_signature => @client_application.secret + "%26" + @access_token.secret
116
+ })
117
+
118
+ env = env_with_params("/invoices", {}, {
119
+ "HTTP_AUTHORIZATION" => auth_str
120
+ })
121
+ @response = setup_rack.call(env)
122
+ @response.first.should == 401
123
+ end
124
+
125
+ it "should not allow to access very secret resources with invalid signature" do
126
+ auth_str = oauth_header({
127
+ :realm => "MoneyBird",
128
+ :oauth_consumer_key => @client_application.key,
129
+ :oauth_token => @access_token.token,
130
+ :oauth_signature_method => "PLAINTEXT",
131
+ :oauth_timestamp => Time.now.to_i,
132
+ :oauth_nonce => Time.now.to_f,
133
+ :oauth_signature => @client_application.secret + "%26" + @access_token.secret + "invalid"
134
+ })
135
+
136
+ env = env_with_params("/invoices", {}, {
137
+ "HTTP_AUTHORIZATION" => auth_str
138
+ })
139
+ @response = setup_rack.call(env)
140
+ @response.first.should == 401
141
+ end
142
+
143
+ it "should not allow to access very secret resources with invalid keys" do
144
+ auth_str = oauth_header({
145
+ :realm => "MoneyBird",
146
+ :oauth_consumer_key => @client_application.key + "invalid",
147
+ :oauth_token => @access_token.token + "invalid",
148
+ :oauth_signature_method => "PLAINTEXT",
149
+ :oauth_timestamp => Time.now.to_i,
150
+ :oauth_nonce => Time.now.to_f,
151
+ :oauth_signature => @client_application.secret + "%26" + @access_token.secret + "invalid"
152
+ })
153
+
154
+ env = env_with_params("/invoices", {}, {
155
+ "HTTP_AUTHORIZATION" => auth_str
156
+ })
157
+ @response = setup_rack.call(env)
158
+ @response.first.should == 401
159
+ end
160
+ end
161
+ end