grosser-rpx_now 0.2 → 0.3
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 +1 -0
- data/README.markdown +24 -3
- data/Rakefile +1 -1
- data/lib/rpx_now.rb +43 -6
- data/rpx_now.gemspec +4 -4
- data/spec/rpx_now_spec.rb +135 -0
- data/spec/spec_helper.rb +36 -0
- metadata +7 -3
data/CHANGELOG
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.3 -- RPXNow::ServerError will be thrown when something is invalid/goes wrong, so watch out (not for invalid tokens in user_data)...
|
data/README.markdown
CHANGED
|
@@ -36,7 +36,7 @@ Controller
|
|
|
36
36
|
----------
|
|
37
37
|
# simple: use defaults
|
|
38
38
|
def rpx_token
|
|
39
|
-
data =
|
|
39
|
+
data = RPXNow.user_data(params[:token],'YOUR RPX API KEY') # :name=>'John Doe',:email=>'john@doe.com',:identifier=>'blug.google.com/openid/dsdfsdfs3f3'
|
|
40
40
|
#when no user_data was found, data is empty, you may want to handle that seperatly...
|
|
41
41
|
#your user model must have an identifier column
|
|
42
42
|
self.current_user = User.find_by_identifier(data[:identifier]) || User.create!(data)
|
|
@@ -44,10 +44,31 @@ Controller
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
# process the raw response yourself:
|
|
47
|
-
|
|
47
|
+
RPXNow.user_data(params[:token],'YOUR RPX API KEY'){|raw| {:email=>raw['profile']['verifiedEmail']}}
|
|
48
48
|
|
|
49
49
|
# request extended parameters (most users and APIs do not supply them)
|
|
50
|
-
|
|
50
|
+
RPXNow.user_data(params[:token],'YOUR RPX API KEY',:extended=>'true'){|raw| ...have a look at the RPX API DOCS...}
|
|
51
|
+
|
|
52
|
+
Advanced: Mappings
|
|
53
|
+
------------------
|
|
54
|
+
You can map your primary keys (e.g. user.id) to identifiers, so that
|
|
55
|
+
users can login to the same account with multiple identifiers.
|
|
56
|
+
#add a mapping
|
|
57
|
+
RPXNow.map(identifier,primary_key,'YOUR RPX API KEY')
|
|
58
|
+
|
|
59
|
+
#remove a mapping
|
|
60
|
+
RPXNow.unmap(identifier,primary_key,'YOUR RPX API KEY')
|
|
61
|
+
|
|
62
|
+
#show mappings
|
|
63
|
+
RPXNow.mappings(primary_key,'YOUR RPX API KEY') # [identifier1,identifier2,...]
|
|
64
|
+
|
|
65
|
+
After a primary key is mapped to an identifier, when a user logs in with this identifier,
|
|
66
|
+
`RPXNow.user_data` will contain his `primaryKey` as `:id`.
|
|
67
|
+
|
|
68
|
+
TODO
|
|
69
|
+
====
|
|
70
|
+
- remove activesupport dependency, use something smaller (json gem looks good but: JSON.parse("{x:1}")==BOOM)
|
|
71
|
+
- validate RPXNow.com SSL certificate
|
|
51
72
|
|
|
52
73
|
Author
|
|
53
74
|
======
|
data/Rakefile
CHANGED
|
@@ -10,7 +10,7 @@ end
|
|
|
10
10
|
|
|
11
11
|
#Gemspec
|
|
12
12
|
porject_name = 'rpx_now'
|
|
13
|
-
Echoe.new(porject_name , '0.
|
|
13
|
+
Echoe.new(porject_name , '0.3') do |p|
|
|
14
14
|
p.description = "Helper to simplify RPX Now user login/creation"
|
|
15
15
|
p.url = "http://github.com/grosser/#{porject_name}"
|
|
16
16
|
p.author = "Michael Grosser"
|
data/lib/rpx_now.rb
CHANGED
|
@@ -1,14 +1,34 @@
|
|
|
1
1
|
require 'activesupport'
|
|
2
2
|
module RPXNow
|
|
3
3
|
extend self
|
|
4
|
+
|
|
5
|
+
# retrieve the users data, or return nil when nothing could be read/token was invalid or data was not found
|
|
4
6
|
def user_data(token,api_key,parameters={})
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
begin
|
|
8
|
+
data = secure_json_post('https://rpxnow.com/api/v2/auth_info',{:token=>token,:apiKey=>api_key}.merge(parameters))
|
|
9
|
+
rescue ServerError
|
|
10
|
+
return nil if $!.to_s =~ /token/ or $!.to_s=~/Data not found/
|
|
11
|
+
raise
|
|
12
|
+
end
|
|
9
13
|
if block_given? then yield(data) else read_user_data_from_response(data) end
|
|
10
14
|
end
|
|
11
15
|
|
|
16
|
+
# maps an identifier to an primary-key (e.g. user.id)
|
|
17
|
+
def map(identifier,primary_key,api_key,options={})
|
|
18
|
+
secure_json_post('https://rpxnow.com/api/v2/map',{:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key}.merge(options))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# un-maps an identifier to an primary-key (e.g. user.id)
|
|
22
|
+
def unmap(identifier,primary_key,api_key)
|
|
23
|
+
secure_json_post('https://rpxnow.com/api/v2/unmap',{:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key})
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# returns an array of identifiers which are mapped to one of your primary-keys (e.g. user.id)
|
|
27
|
+
def mappings(primary_key,api_key)
|
|
28
|
+
data = secure_json_post('https://rpxnow.com/api/v2/mappings',{:primaryKey=>primary_key,:apiKey=>api_key})
|
|
29
|
+
data['identifiers']
|
|
30
|
+
end
|
|
31
|
+
|
|
12
32
|
def embed_code(subdomain,url)
|
|
13
33
|
<<EOF
|
|
14
34
|
<iframe src="https://#{subdomain}.rpxnow.com/openid/embed?token_url=#{url}"
|
|
@@ -19,7 +39,7 @@ EOF
|
|
|
19
39
|
|
|
20
40
|
def popup_code(text,subdomain,url,options={})
|
|
21
41
|
<<EOF
|
|
22
|
-
<a class="rpxnow" onclick="return false;" href="https
|
|
42
|
+
<a class="rpxnow" onclick="return false;" href="https://#{subdomain}.rpxnow.com/openid/v2/signin?token_url=#{url}">
|
|
23
43
|
#{text}
|
|
24
44
|
</a>
|
|
25
45
|
<script src="https://rpxnow.com/openid/v2/widget" type="text/javascript"></script>
|
|
@@ -43,6 +63,14 @@ private
|
|
|
43
63
|
data[:identifier] = user_data['identifier']
|
|
44
64
|
data[:email] = user_data['verifiedEmail'] || user_data['email']
|
|
45
65
|
data[:name] = user_data['displayName'] || user_data['preferredUsername'] || data[:email].sub(/@.*/,'')
|
|
66
|
+
data[:id] = user_data['primaryKey'].to_i unless user_data['primaryKey'].to_s.empty?
|
|
67
|
+
data
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def secure_json_post(url,data={})
|
|
71
|
+
data = ActiveSupport::JSON.decode(post(url,data))
|
|
72
|
+
raise ServerError.new(data['err']) if data['err']
|
|
73
|
+
raise ServerError.new(data.inspect) unless data['stat']=='ok'
|
|
46
74
|
data
|
|
47
75
|
end
|
|
48
76
|
|
|
@@ -53,9 +81,18 @@ private
|
|
|
53
81
|
if url.scheme == 'https'
|
|
54
82
|
require 'net/https'
|
|
55
83
|
http.use_ssl = true
|
|
84
|
+
#TODO do we really want to verify the certificate? http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/
|
|
85
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
56
86
|
end
|
|
57
87
|
resp, data = http.post(url.path, data.to_query)
|
|
58
88
|
raise "POST FAILED:"+resp.inspect unless resp.is_a? Net::HTTPOK
|
|
59
|
-
|
|
89
|
+
data
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class ServerError < Exception
|
|
93
|
+
#to_s returns message(which is a hash...)
|
|
94
|
+
def to_s
|
|
95
|
+
super.to_s
|
|
96
|
+
end
|
|
60
97
|
end
|
|
61
98
|
end
|
data/rpx_now.gemspec
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
4
|
s.name = %q{rpx_now}
|
|
5
|
-
s.version = "0.
|
|
5
|
+
s.version = "0.3"
|
|
6
6
|
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
8
8
|
s.authors = ["Michael Grosser"]
|
|
9
|
-
s.date = %q{2009-01-
|
|
9
|
+
s.date = %q{2009-01-28}
|
|
10
10
|
s.description = %q{Helper to simplify RPX Now user login/creation}
|
|
11
11
|
s.email = %q{grosser.michael@gmail.com}
|
|
12
|
-
s.extra_rdoc_files = ["lib/rpx_now.rb", "README.markdown"]
|
|
13
|
-
s.files = ["Manifest", "lib/rpx_now.rb", "
|
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/rpx_now.rb", "README.markdown"]
|
|
13
|
+
s.files = ["Manifest", "CHANGELOG", "lib/rpx_now.rb", "spec/rpx_now_spec.rb", "spec/spec_helper.rb", "rpx_now.gemspec", "init.rb", "Rakefile", "README.markdown"]
|
|
14
14
|
s.has_rdoc = true
|
|
15
15
|
s.homepage = %q{http://github.com/grosser/rpx_now}
|
|
16
16
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Rpx_now", "--main", "README.markdown"]
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
|
2
|
+
|
|
3
|
+
API_KEY = '4b339169026742245b754fa338b9b0aebbd0a733'
|
|
4
|
+
|
|
5
|
+
describe RPXNow do
|
|
6
|
+
describe :embed_code do
|
|
7
|
+
it "contains the subdomain" do
|
|
8
|
+
RPXNow.embed_code('xxx','my_url').should =~ /xxx/
|
|
9
|
+
end
|
|
10
|
+
it "contains the url" do
|
|
11
|
+
RPXNow.embed_code('xxx','my_url').should =~ /token_url=my_url/
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe :popup_code do
|
|
16
|
+
it "defaults to english" do
|
|
17
|
+
RPXNow.popup_code('x','y','z').should =~ /RPXNOW.language_preference = 'en'/
|
|
18
|
+
end
|
|
19
|
+
it "has a changeable language" do
|
|
20
|
+
RPXNow.popup_code('x','y','z',:language=>'de').should =~ /RPXNOW.language_preference = 'de'/
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe :user_data do
|
|
25
|
+
def fake_response
|
|
26
|
+
'{"profile":{"verifiedEmail":"grosser.michael@googlemail.com","displayName":"Michael Grosser","preferredUsername":"grosser.michael","identifier":"https:\/\/www.google.com\/accounts\/o8\/id?id=AItOawmaOlyYezg_WfbgP_qjaUyHjmqZD9qNIVM","email":"grosser.michael@gmail.com"},"stat":"ok"}'
|
|
27
|
+
end
|
|
28
|
+
it "is empty when used with an invalid token" do
|
|
29
|
+
RPXNow.user_data('xxxx',API_KEY).should == nil
|
|
30
|
+
end
|
|
31
|
+
it "is empty when used with an unknown token" do
|
|
32
|
+
RPXNow.user_data('60d8c6374f4e9d290a7b55f39da7cc6435aef3d3',API_KEY).should == nil
|
|
33
|
+
end
|
|
34
|
+
it "parses JSON response to user data" do
|
|
35
|
+
RPXNow.expects(:post).returns fake_response
|
|
36
|
+
RPXNow.user_data('','x').should == {:name=>'Michael Grosser',:email=>'grosser.michael@googlemail.com',:identifier=>"https://www.google.com/accounts/o8/id?id=AItOawmaOlyYezg_WfbgP_qjaUyHjmqZD9qNIVM"}
|
|
37
|
+
end
|
|
38
|
+
it "adds a :id when primaryKey was returned" do
|
|
39
|
+
RPXNow.expects(:post).returns fake_response.sub('"verifiedEmail"','primaryKey:"2","verifiedEmail"')
|
|
40
|
+
RPXNow.user_data('','x')[:id].should == 2
|
|
41
|
+
end
|
|
42
|
+
it "hands JSON response to supplied block" do
|
|
43
|
+
RPXNow.expects(:post).returns "{x:1,stat:'ok'}"
|
|
44
|
+
response = nil
|
|
45
|
+
RPXNow.user_data('','x'){|data| response = data}
|
|
46
|
+
response.should == {'x'=>1,'stat'=>'ok'}
|
|
47
|
+
end
|
|
48
|
+
it "returns what the supplied block returned" do
|
|
49
|
+
RPXNow.expects(:post).returns "{x:1,stat:'ok'}"
|
|
50
|
+
RPXNow.user_data('','x'){|data| "x"}.should == 'x'
|
|
51
|
+
end
|
|
52
|
+
it "can send additional parameters" do
|
|
53
|
+
RPXNow.expects(:post).with{|url,data|
|
|
54
|
+
data[:extended].should == 'true'
|
|
55
|
+
}.returns fake_response
|
|
56
|
+
RPXNow.user_data('','x',:extended=>'true')
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe :read_user_data_from_response do
|
|
61
|
+
it "reads secondary names" do
|
|
62
|
+
RPXNow.send(:read_user_data_from_response,{'profile'=>{'preferredUsername'=>'1'}})[:name].should == '1'
|
|
63
|
+
end
|
|
64
|
+
it "parses email when no name is found" do
|
|
65
|
+
RPXNow.send(:read_user_data_from_response,{'profile'=>{'email'=>'1@xxx.com'}})[:name].should == '1'
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe :secure_json_post do
|
|
70
|
+
it "parses json when status is ok" do
|
|
71
|
+
RPXNow.expects(:post).returns '{stat:"ok",data:"xx"}'
|
|
72
|
+
RPXNow.send(:secure_json_post,'xx')['data'].should == 'xx'
|
|
73
|
+
end
|
|
74
|
+
it "raises when there is a communication error" do
|
|
75
|
+
RPXNow.expects(:post).returns '{"err":"wtf",stat:"ok"}'
|
|
76
|
+
lambda{RPXNow.send(:secure_json_post,'xx')}.should raise_error RPXNow::ServerError
|
|
77
|
+
end
|
|
78
|
+
it "raises when status is not ok" do
|
|
79
|
+
RPXNow.expects(:post).returns '{"stat":"err"}'
|
|
80
|
+
lambda{RPXNow.send(:secure_json_post,'xx')}.should raise_error RPXNow::ServerError
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe :mappings do
|
|
85
|
+
it "parses JSON response to unmap data" do
|
|
86
|
+
RPXNow.expects(:post).returns '{"stat":"ok", "identifiers": ["http://test.myopenid.com/"]}'
|
|
87
|
+
RPXNow.mappings(1, "x").should == ["http://test.myopenid.com/"]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe :map do
|
|
92
|
+
it "adds a mapping" do
|
|
93
|
+
RPXNow.expects(:post).returns '{"stat":"ok"}'
|
|
94
|
+
RPXNow.map('http://test.myopenid.com',1, API_KEY)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe :unmap do
|
|
99
|
+
it "unmaps a indentifier" do
|
|
100
|
+
RPXNow.expects(:post).returns '{"stat":"ok"}'
|
|
101
|
+
RPXNow.unmap('http://test.myopenid.com', 1, "x")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe :mapping_integration do
|
|
106
|
+
before do
|
|
107
|
+
@k1 = 'http://test.myopenid.com'
|
|
108
|
+
RPXNow.unmap(@k1, 1, API_KEY)
|
|
109
|
+
@k2 = 'http://test-2.myopenid.com'
|
|
110
|
+
RPXNow.unmap(@k2, 1, API_KEY)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "has no mappings when nothing was mapped" do
|
|
114
|
+
RPXNow.mappings(1,API_KEY).should == []
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "unmaps mapped keys" do
|
|
118
|
+
RPXNow.map(@k2, 1, API_KEY)
|
|
119
|
+
RPXNow.unmap(@k2, 1, API_KEY)
|
|
120
|
+
RPXNow.mappings(1, API_KEY).should == []
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "maps keys to a primary key and then retrieves them" do
|
|
124
|
+
RPXNow.map(@k1, 1, API_KEY)
|
|
125
|
+
RPXNow.map(@k2, 1, API_KEY)
|
|
126
|
+
RPXNow.mappings(1,API_KEY).sort.should == [@k2,@k1]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "does not add duplicate mappings" do
|
|
130
|
+
RPXNow.map(@k1, 1, API_KEY)
|
|
131
|
+
RPXNow.map(@k1, 1, API_KEY)
|
|
132
|
+
RPXNow.mappings(1,API_KEY).should == [@k1]
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# ---- requirements
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
require 'spec'
|
|
4
|
+
require 'mocha'
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# ---- rspec
|
|
10
|
+
Spec::Runner.configure do |config|
|
|
11
|
+
config.mock_with :mocha
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ---- bugfix
|
|
16
|
+
#`exit?': undefined method `run?' for Test::Unit:Module (NoMethodError)
|
|
17
|
+
#can be solved with require test/unit but this will result in extra test-output
|
|
18
|
+
module Test
|
|
19
|
+
module Unit
|
|
20
|
+
def self.run?
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# ---- setup environment/plugin
|
|
28
|
+
require File.expand_path("../init", File.dirname(__FILE__))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ---- Helpers
|
|
32
|
+
def pending_it(text,&block)
|
|
33
|
+
it text do
|
|
34
|
+
pending(&block)
|
|
35
|
+
end
|
|
36
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: grosser-rpx_now
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: "0.
|
|
4
|
+
version: "0.3"
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Grosser
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2009-01-
|
|
12
|
+
date: 2009-01-28 00:00:00 -08:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
@@ -37,15 +37,19 @@ executables: []
|
|
|
37
37
|
extensions: []
|
|
38
38
|
|
|
39
39
|
extra_rdoc_files:
|
|
40
|
+
- CHANGELOG
|
|
40
41
|
- lib/rpx_now.rb
|
|
41
42
|
- README.markdown
|
|
42
43
|
files:
|
|
43
44
|
- Manifest
|
|
45
|
+
- CHANGELOG
|
|
44
46
|
- lib/rpx_now.rb
|
|
47
|
+
- spec/rpx_now_spec.rb
|
|
48
|
+
- spec/spec_helper.rb
|
|
49
|
+
- rpx_now.gemspec
|
|
45
50
|
- init.rb
|
|
46
51
|
- Rakefile
|
|
47
52
|
- README.markdown
|
|
48
|
-
- rpx_now.gemspec
|
|
49
53
|
has_rdoc: true
|
|
50
54
|
homepage: http://github.com/grosser/rpx_now
|
|
51
55
|
post_install_message:
|