warden_oauth_provider 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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