rack-oauth2-server 1.3.0 → 1.3.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 +10 -0
- data/Gemfile +0 -1
- data/README.rdoc +72 -1
- data/VERSION +1 -1
- data/bin/oauth2-server +107 -0
- data/lib/rack/oauth2/admin/css/screen.css +45 -9
- data/lib/rack/oauth2/admin/images/oauth-2.png +0 -0
- data/lib/rack/oauth2/admin/js/application.js +26 -19
- data/lib/rack/oauth2/admin/views/client.tmpl +3 -2
- data/lib/rack/oauth2/admin/views/clients.tmpl +14 -1
- data/lib/rack/oauth2/admin/views/index.html +10 -1
- data/lib/rack/oauth2/models.rb +2 -0
- data/lib/rack/oauth2/models/client.rb +9 -0
- data/lib/rack/oauth2/server/admin.rb +8 -1
- data/rack-oauth2-server.gemspec +1 -1
- data/test/rails/log/test.log +4828 -0
- metadata +7 -5
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
2010-11-07 version 1.3.1
|
2
|
+
|
3
|
+
Added command line tool, helps you get started and setup:
|
4
|
+
$ oauth2-server setup --db my_db
|
5
|
+
|
6
|
+
Added a touch of color to the UI and ability to delete a client.
|
7
|
+
|
8
|
+
You can not sign out of the Web console.
|
9
|
+
|
10
|
+
|
1
11
|
2010-11-07 version 1.3.0
|
2
12
|
|
3
13
|
Added OAuth authorization console.
|
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -281,7 +281,13 @@ Clients can also register a redirect URL. This is optional but highly
|
|
281
281
|
recommended for better security, preventing other applications from hijackin
|
282
282
|
the client's ID/secret.
|
283
283
|
|
284
|
-
|
284
|
+
You can register clients using the command line tool +oauth2-server+:
|
285
|
+
|
286
|
+
$ oauth2-server register --db my_db
|
287
|
+
|
288
|
+
Or you can register clients using the Web-based OAuth console, see below.
|
289
|
+
|
290
|
+
Programatically, registering a new client is as simple as:
|
285
291
|
|
286
292
|
$ ./script/console
|
287
293
|
Loading development environment (Rails 2.3.8)
|
@@ -332,6 +338,10 @@ when making POST request, as a form field:
|
|
332
338
|
$ curl -i http://localhost:3000/api/read?oauth_token=e57807eb99f8c29f60a27a75a80fec6e
|
333
339
|
$ curl -i http://localhost:3000/api/update -F name=Superman -F oauth_token=e57807eb99f8c29f60a27a75a80fec6e
|
334
340
|
|
341
|
+
You'll need to set the option +param_authentication+ to true. Watch out, since
|
342
|
+
this query parameter could conflict with OAuth 1.0 authorization responses that
|
343
|
+
also use +oauth_token+ for a different purpose.
|
344
|
+
|
335
345
|
Here's a neat trick. You can create a +.curlrc+ file and load it using the +-K+ option:
|
336
346
|
|
337
347
|
$ cat .curlrc
|
@@ -344,6 +354,67 @@ server you +curl+. Useful for development, testing, just don't use it with any
|
|
344
354
|
production access tokens.
|
345
355
|
|
346
356
|
|
357
|
+
== OAuth Web Console
|
358
|
+
|
359
|
+
We haz it, and it's pretty rad:
|
360
|
+
|
361
|
+
http://github.com/downloads/flowtown/rack-oauth2-server/OAuth%20Console%20-%20All%20Clients.png
|
362
|
+
|
363
|
+
To get the console running, you'll need to do the following. First, you'll need
|
364
|
+
to register a new client application that can access the OAuth console, with a
|
365
|
+
redirect_uri that points to where you plan the Web console to live. This URL
|
366
|
+
must end with "/admin", for example, "http://example.com/oauth/admin".
|
367
|
+
|
368
|
+
The easiest way to do this is to run the +oauth2-sever+ command line tool:
|
369
|
+
|
370
|
+
$ oauth2-server setup --db my_db
|
371
|
+
|
372
|
+
Next, in your application, make sure to ONLY AUTHORIZE ADMINISTRATORS to access
|
373
|
+
the console, by granting them access to the +oauth-admin+ scope. For example:
|
374
|
+
|
375
|
+
def authorize
|
376
|
+
# Only admins allowed to authorize the scope oauth-admin
|
377
|
+
if oauth.scope.include?("oauth-admin") && !current_user.admin?
|
378
|
+
oauth.deny! oauth.authorization
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
Make sure you do that, or you'll allow anyone access to the OAuth Web console.
|
383
|
+
|
384
|
+
Next, mount the OAuth Web console as part of your application, and feed it the
|
385
|
+
client ID/secret. For example, for Rails add this to +config/environment.rb+:
|
386
|
+
|
387
|
+
Rails::Initializer.run do |config|
|
388
|
+
. . .
|
389
|
+
config.middleware.use Rack::OAuth2::Server::Admin.mount
|
390
|
+
Rack::OAuth2::Server::Admin.set :client_id, "4dca20453e4859cb000007"
|
391
|
+
Rack::OAuth2::Server::Admin.set :client_secret, "981fa734e110496fcf667cbf52fbaf03"
|
392
|
+
end
|
393
|
+
|
394
|
+
For Sinatra, Padrino and other Rack-based applications, you'll want to mount
|
395
|
+
like so (e.g. in +config.ru+):
|
396
|
+
|
397
|
+
Rack::Builder.new do
|
398
|
+
map("/oauth/admin") { run Rack::OAuth2::Server::Admin }
|
399
|
+
map("/") { run MyApp }
|
400
|
+
end
|
401
|
+
Rack::OAuth2::Server::Admin.set :client_id, "4dca20453e4859cb000007"
|
402
|
+
Rack::OAuth2::Server::Admin.set :client_secret, "981fa734e110496fcf667cbf52fbaf03"
|
403
|
+
|
404
|
+
Next, open your browser to http://example.com/oauth/admin, or wherever you
|
405
|
+
mounted the console.
|
406
|
+
|
407
|
+
The OAuth Web console is a single-page client application that operates by
|
408
|
+
accessing the OAuth API. The API is mounted at /oauth/admin/api (basically /api
|
409
|
+
relative to the console), you can access it yourself if you have an access
|
410
|
+
token with the scope +oauth-admin+.
|
411
|
+
|
412
|
+
To get the access token, the console first redirects you to the path
|
413
|
+
+/oauth/authorize+, which it expects to be the OAuth 2.0 authorization
|
414
|
+
endpoint. If you need to use a different endpoint, simply set the :authorize
|
415
|
+
option to that URL.
|
416
|
+
|
417
|
+
|
347
418
|
== Mandatory ASCII Diagram
|
348
419
|
|
349
420
|
This is briefly what the authorization flow looks like, how the workload is
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.3.
|
1
|
+
1.3.1
|
data/bin/oauth2-server
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
3
|
+
require "rack/oauth2/models"
|
4
|
+
require "uri"
|
5
|
+
include Rack::OAuth2
|
6
|
+
|
7
|
+
|
8
|
+
if (i = ARGV.index("--db")) && ARGV[i+1]
|
9
|
+
url = ARGV[i + 1]
|
10
|
+
uri = URI.parse(url)
|
11
|
+
uri = URI.parse("mongo://#{url}") if uri.opaque
|
12
|
+
db = uri.path.sub(/^\//, "")
|
13
|
+
conn = Mongo::Connection.new(uri.host, uri.port)
|
14
|
+
coon.add_auth db, uri.user, uri.password if uri.user
|
15
|
+
Server.database = conn[db]
|
16
|
+
ARGV[i,2] = []
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
case ARGV[0]
|
21
|
+
when "list"
|
22
|
+
fail "No database. Use the --db option to tell us which database to use" unless Server.database
|
23
|
+
Server::Client.all.each do |client|
|
24
|
+
next if client.revoked
|
25
|
+
print "%-30s\t%s\n" % [client.display_name, client.link]
|
26
|
+
print " ID %s\tSecret %s\n" % [client.id, client.secret]
|
27
|
+
print "\n"
|
28
|
+
end
|
29
|
+
when "register"
|
30
|
+
fail "No database. Use the --db option to tell us which database to use" unless Server.database
|
31
|
+
begin
|
32
|
+
print "Application name:\t"
|
33
|
+
display_name = $stdin.gets
|
34
|
+
print "Application URL:\t"
|
35
|
+
link = $stdin.gets
|
36
|
+
print "Redirect URI:\t\t"
|
37
|
+
redirect_uri = $stdin.gets
|
38
|
+
client = Server::Client.create(:display_name=>display_name, :link=>link, :redirect_uri=>redirect_uri)
|
39
|
+
rescue
|
40
|
+
puts "\nFailed to register client: #{$1}"
|
41
|
+
exit -1
|
42
|
+
end
|
43
|
+
puts "Registered #{client.display_name}"
|
44
|
+
puts "ID\t#{client.id}"
|
45
|
+
puts "Secret\t#{client.secret}"
|
46
|
+
when "setup"
|
47
|
+
fail "No database. Use the --db option to tell us which database to use" unless Server.database
|
48
|
+
puts "Where would you mount the Web console? This is a URL that must end with /admin,"
|
49
|
+
puts "for example, http://example.com/oauth/admin"
|
50
|
+
uri = URI.parse($stdin.gets)
|
51
|
+
begin
|
52
|
+
uri.normalize!
|
53
|
+
fail "No an HTTP/S URL" unless uri.absolute? && %{http https}.include?(uri.scheme)
|
54
|
+
fail "Path must end with /admin" unless uri.path[/\/admin$/]
|
55
|
+
client = Server::Client.create(:display_name=>"OAuth Console", :link=>uri.to_s,
|
56
|
+
:image_url=>"#{uri.to_s}/images/oauth-2.png", :redirect_uri=>uri.to_s)
|
57
|
+
rescue
|
58
|
+
puts "\nFailed to register client: #{$!}"
|
59
|
+
exit -1
|
60
|
+
end
|
61
|
+
print <<-TEXT
|
62
|
+
Make sure you ONLY authorize administrators to use the oauth-admin scope.
|
63
|
+
For example:
|
64
|
+
|
65
|
+
def authorize
|
66
|
+
# Only admins allowed to authorize the scope oauth-admin
|
67
|
+
if oauth.scope.include?("oauth-admin") && !current_user.admin?
|
68
|
+
oauth.deny! oauth.authorization
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
Rails 2.x, add the following to config/environment.rb:
|
73
|
+
|
74
|
+
config.middleware.use Rack::OAuth2::Server::Admin.mount "#{uri.path}"
|
75
|
+
Rack::OAuth2::Server::Admin.set :client_id, "#{client.id}"
|
76
|
+
Rack::OAuth2::Server::Admin.set :client_secret, "#{client.secret}"
|
77
|
+
|
78
|
+
Sinatra, Padrino and other Rack applications, mount the console:
|
79
|
+
|
80
|
+
Rack::Builder.new do
|
81
|
+
map("#{uri.path}") { run Rack::OAuth2::Server::Admin }
|
82
|
+
map("/") { run MyApp }
|
83
|
+
end
|
84
|
+
Rack::OAuth2::Server::Admin.set :client_id, "#{client.id}"
|
85
|
+
Rack::OAuth2::Server::Admin.set :client_secret, "#{client.secret}"
|
86
|
+
|
87
|
+
The console will authorize access by redirecting to
|
88
|
+
https://#{uri.host}/oauth/authorize
|
89
|
+
|
90
|
+
If this is not your OAuth 2.0 authorization endpoint, you can change it by
|
91
|
+
setting the :authorize option.
|
92
|
+
TEXT
|
93
|
+
else
|
94
|
+
print <<-TEXT
|
95
|
+
Usage: oauth2-server [options] COMMAND [args]
|
96
|
+
|
97
|
+
Commands:
|
98
|
+
list Lists all active clients
|
99
|
+
register Register a new client application
|
100
|
+
setup Create new admin account and help you
|
101
|
+
setup the OAuth Web console
|
102
|
+
|
103
|
+
Options:
|
104
|
+
--db database Database name or connection URL
|
105
|
+
TEXT
|
106
|
+
exit -1
|
107
|
+
end
|
@@ -1,5 +1,9 @@
|
|
1
|
+
html {
|
2
|
+
background: #eee;
|
3
|
+
}
|
1
4
|
body {
|
2
5
|
margin: 0;
|
6
|
+
padding: 0;
|
3
7
|
width: 100%;
|
4
8
|
font: 12pt "Helvetica", "Lucida Sans", "Verdana";
|
5
9
|
}
|
@@ -75,20 +79,45 @@ button:active { background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(0
|
|
75
79
|
}
|
76
80
|
|
77
81
|
#header {
|
78
|
-
margin: 0
|
82
|
+
margin: 0;
|
83
|
+
padding: 2em;
|
84
|
+
background: #fff;
|
85
|
+
background: -webkit-gradient(linear, left top, left bottom, from(#ccf), to(#fff));
|
86
|
+
background: -moz-linear-gradient(top, #ccf, #fff);
|
79
87
|
}
|
80
88
|
#header .title {
|
81
|
-
font-size:
|
89
|
+
font-size: 18pt;
|
82
90
|
font-weight: bold;
|
83
|
-
color: #000;
|
84
|
-
text-decoration: none;
|
85
|
-
margin: 0.6em 0;
|
86
91
|
display: block;
|
87
92
|
text-align: right;
|
93
|
+
line-height: 32px;
|
94
|
+
}
|
95
|
+
#header .title a {
|
96
|
+
color: #000;
|
97
|
+
text-decoration: none;
|
98
|
+
}
|
99
|
+
#header .title img {
|
100
|
+
width: 32px;
|
101
|
+
height: 32px;
|
102
|
+
vertical-align: bottom;
|
103
|
+
}
|
104
|
+
#header .signout {
|
105
|
+
float: right;
|
106
|
+
font-size: 11pt;
|
88
107
|
}
|
89
108
|
|
90
109
|
#main {
|
91
|
-
|
110
|
+
padding: 0 2em 4em 2em;
|
111
|
+
background: #fff;
|
112
|
+
}
|
113
|
+
#footer {
|
114
|
+
background: #eee;
|
115
|
+
background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#eee));
|
116
|
+
background: -moz-linear-gradient(top, #fff, #eee);
|
117
|
+
color: #666;
|
118
|
+
border-top: 1px solid transparent;
|
119
|
+
font-size: 90%;
|
120
|
+
padding: 0 2em 2em 2em;
|
92
121
|
}
|
93
122
|
|
94
123
|
table {
|
@@ -97,6 +126,7 @@ table {
|
|
97
126
|
empty-cells: show;
|
98
127
|
border-collapse: separate;
|
99
128
|
border-spacing: 0px;
|
129
|
+
margin-top: 2em;
|
100
130
|
}
|
101
131
|
table th {
|
102
132
|
text-align: left;
|
@@ -177,7 +207,7 @@ table.tokens td.scope {
|
|
177
207
|
|
178
208
|
.badges {
|
179
209
|
list-style: none;
|
180
|
-
margin:
|
210
|
+
margin: 0;
|
181
211
|
padding: 0;
|
182
212
|
text-align: right;
|
183
213
|
width: 100%;
|
@@ -211,13 +241,19 @@ table.tokens td.scope {
|
|
211
241
|
height: 24px;
|
212
242
|
vertical-align: bottom;
|
213
243
|
}
|
214
|
-
.client .details a
|
215
|
-
margin: 0 0.3em 0
|
244
|
+
.client .details a {
|
245
|
+
margin: 0 0.3em 0 0;
|
216
246
|
}
|
217
247
|
.client .details .meta {
|
218
248
|
color: #888;
|
219
249
|
font-size: 10pt;
|
220
250
|
}
|
251
|
+
|
252
|
+
.client.new, .client.edit {
|
253
|
+
margin: 0;
|
254
|
+
padding: 1em;
|
255
|
+
border: 1px solid #eee;
|
256
|
+
}
|
221
257
|
.client.new>#image, .client.edit>#image {
|
222
258
|
float: left;
|
223
259
|
margin: 0 12px 0 0;
|
Binary file
|
@@ -64,6 +64,20 @@ Sammy("#main", function(app) {
|
|
64
64
|
}
|
65
65
|
})
|
66
66
|
});
|
67
|
+
// Delete/revoke client
|
68
|
+
this.del("#/client/:id", function(context) {
|
69
|
+
$.ajax({ type: "post", url: api + "/client/" + context.params.id,
|
70
|
+
data: { _method: "delete" },
|
71
|
+
success: function() { context.redirect("#/") }
|
72
|
+
});
|
73
|
+
});
|
74
|
+
this.post("#/client/:id/revoke", function(context) {
|
75
|
+
$.post(api + "/client/" + context.params.id + "/revoke", function() { app.refresh() });
|
76
|
+
});
|
77
|
+
// Revoke token
|
78
|
+
this.post("#/token/:id/revoke", function(context) {
|
79
|
+
$.post(api + "/token/" + context.params.id + "/revoke", function() { app.refresh() });
|
80
|
+
});
|
67
81
|
// View single client
|
68
82
|
this.get("#/client/:id", function(context) {
|
69
83
|
$.getJSON(api + "/client/" + context.params.id, function(client) {
|
@@ -101,29 +115,22 @@ Sammy("#main", function(app) {
|
|
101
115
|
}
|
102
116
|
});
|
103
117
|
});
|
118
|
+
// Signout
|
119
|
+
this.get("#/signout", function(context) {
|
120
|
+
app.session("oauth.token", null);
|
121
|
+
context.redirect(document.location.protocol + "//" + document.location.host);
|
122
|
+
});
|
104
123
|
|
105
|
-
//
|
106
|
-
$("a[data-method
|
124
|
+
// Links that use forms for various methods (i.e. post, delete).
|
125
|
+
$("a[data-method]").live("click", function(evt) {
|
107
126
|
evt.preventDefault();
|
108
127
|
var link = $(this);
|
109
128
|
if (link.attr("data-confirm") && !confirm(link.attr("data-confirm")))
|
110
|
-
return;
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
});
|
116
|
-
// Link to reveal/hide client ID/secret
|
117
|
-
$("td.secrets a[rel=toggle]").live("click", function(evt) {
|
118
|
-
evt.preventDefault();
|
119
|
-
var dl = $(this).next("dl");
|
120
|
-
if (dl.is(":visible")) {
|
121
|
-
$(this).html("Reveal");
|
122
|
-
dl.hide();
|
123
|
-
} else {
|
124
|
-
$(this).html("Hide");
|
125
|
-
dl.show();
|
126
|
-
}
|
129
|
+
return fasle;
|
130
|
+
var method = link.attr("data-method") || "get",
|
131
|
+
form = $("<form>", { style: "display:none", method: method, action: link.attr("href") });
|
132
|
+
app.$element().append(form);
|
133
|
+
form.submit();
|
127
134
|
});
|
128
135
|
// Error/notice at top of screen
|
129
136
|
var noticeTimeout;
|
@@ -3,8 +3,9 @@
|
|
3
3
|
<a href="${link}" class="name">{{if imageUrl}}<img src="${imageUrl}">{{/if}} ${displayName}</a>
|
4
4
|
<a href="#/client/${id}/edit" rel="edit">Edit</a>
|
5
5
|
{{if !revoked}}
|
6
|
-
<a href="
|
6
|
+
<a href="#/client/${id}/revoke" data-method="post" data-confirm="There is no undo. Are you really really sure?" rel="revoke">Revoke</a>
|
7
7
|
{{/if}}
|
8
|
+
<a href="#/client/${id}" data-method="delete" data-confirm="There is no undo. Are you really really sure?" rel="delete">Delete</a>
|
8
9
|
<div class="meta">
|
9
10
|
Created {{html $.shortdate(revoked)}}
|
10
11
|
{{if revoked}}Revoked {{html $.shortdate(revoked)}}{{/if}}
|
@@ -34,7 +35,7 @@
|
|
34
35
|
{{if revoked}}
|
35
36
|
{{html $.shortdate(revoked)}}
|
36
37
|
{{else}}
|
37
|
-
<a href="
|
38
|
+
<a href="#/token/${token}/revoke" data-method="post" data-confirm="Are you sure?" rel="revoke">Revoke</a>
|
38
39
|
{{/if}}
|
39
40
|
</td>
|
40
41
|
</tr>
|
@@ -17,7 +17,7 @@
|
|
17
17
|
<td class="name">
|
18
18
|
<a href="#/client/${id}">
|
19
19
|
{{if imageUrl}}<img src="${imageUrl}">{{/if}}
|
20
|
-
${displayName}
|
20
|
+
${displayName.trim() == "" ? "untitled" : displayName}
|
21
21
|
</a>
|
22
22
|
</td>
|
23
23
|
<td class="secrets">
|
@@ -34,3 +34,16 @@
|
|
34
34
|
{{/each}}
|
35
35
|
</table>
|
36
36
|
</div>
|
37
|
+
<script type="text/javascript">
|
38
|
+
$("td.secrets a[rel=toggle]").click(function(evt) {
|
39
|
+
evt.preventDefault();
|
40
|
+
var dl = $(this).next("dl");
|
41
|
+
if (dl.is(":visible")) {
|
42
|
+
$(this).html("Reveal");
|
43
|
+
dl.hide();
|
44
|
+
} else {
|
45
|
+
$(this).html("Hide");
|
46
|
+
dl.show();
|
47
|
+
}
|
48
|
+
});
|
49
|
+
</script>
|
@@ -12,11 +12,20 @@
|
|
12
12
|
<script src="admin/js/sammy.title.js" type="text/javascript"></script>
|
13
13
|
<script src="admin/js/underscore.js" type="text/javascript"></script>
|
14
14
|
<script src="admin/js/application.js" type="text/javascript"></script>
|
15
|
+
<link rel="shortcut icon" href="admin/images/oauth-2.png">
|
15
16
|
</head>
|
16
17
|
<body>
|
17
18
|
<div id="notice" style="display:none"></div>
|
18
|
-
<div id="header"
|
19
|
+
<div id="header">
|
20
|
+
<div class="title">
|
21
|
+
<a href="#/"><img src="admin/images/oauth-2.png"> OAuth Console</a>
|
22
|
+
</div>
|
23
|
+
<a href="#/signout" class="signout">Sign out</a>
|
24
|
+
</div>
|
19
25
|
<div id="main"></div>
|
26
|
+
<div id="footer">
|
27
|
+
<p>Powered by <a href="http://github.com/flowtown/rack-oauth2-server">Rack::OAuth2::Server</a></p>
|
28
|
+
</div>
|
20
29
|
<script>
|
21
30
|
var loading = new Image();
|
22
31
|
loading.src = "admin/images/loading.gif";
|