danski-ooh-auth 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/Rakefile +58 -0
- data/app/controllers/application.rb +16 -0
- data/app/controllers/authenticating_clients.rb +60 -0
- data/app/controllers/tokens.rb +94 -0
- data/app/helpers/application_helper.rb +64 -0
- data/app/helpers/authenticating_clients_helper.rb +5 -0
- data/app/helpers/authentications_helper.rb +5 -0
- data/app/models/authenticating_client.rb +12 -0
- data/app/models/authenticating_client/dm_authenticating_client.rb +71 -0
- data/app/models/token.rb +12 -0
- data/app/models/token/dm_token.rb +150 -0
- data/app/views/authenticating_clients/_help.html.erb +1 -0
- data/app/views/authenticating_clients/edit.html.erb +27 -0
- data/app/views/authenticating_clients/index.html.erb +24 -0
- data/app/views/authenticating_clients/new.html.erb +47 -0
- data/app/views/authenticating_clients/show.html.erb +40 -0
- data/app/views/layout/ooh_auth.html.erb +23 -0
- data/app/views/tokens/create.html.erb +34 -0
- data/app/views/tokens/edit.html.erb +4 -0
- data/app/views/tokens/new.html.erb +52 -0
- data/app/views/tokens/show.html.erb +1 -0
- data/lib/ooh-auth.rb +103 -0
- data/lib/ooh-auth/authentication_mixin.rb +13 -0
- data/lib/ooh-auth/controller_mixin.rb +38 -0
- data/lib/ooh-auth/key_generators.rb +57 -0
- data/lib/ooh-auth/merbtasks.rb +103 -0
- data/lib/ooh-auth/request_verification_mixin.rb +160 -0
- data/lib/ooh-auth/slicetasks.rb +18 -0
- data/lib/ooh-auth/spectasks.rb +65 -0
- data/lib/ooh-auth/strategies/oauth.rb +16 -0
- data/public/javascripts/master.js +0 -0
- data/public/stylesheets/master.css +2 -0
- data/readme.markdown +43 -0
- data/spec/controllers/application_spec.rb +35 -0
- data/spec/controllers/authenticating_clients_spec.rb +119 -0
- data/spec/controllers/tokens_spec.rb +173 -0
- data/spec/merb-auth-slice-fullfat_spec.rb +41 -0
- data/spec/models/authenticating_client_spec.rb +44 -0
- data/spec/models/oauth_strategy_spec.rb +48 -0
- data/spec/models/request_verification_mixin_spec.rb +121 -0
- data/spec/models/token_spec.rb +139 -0
- data/spec/spec_fixtures.rb +19 -0
- data/spec/spec_helper.rb +107 -0
- data/stubs/app/controllers/application.rb +2 -0
- data/stubs/app/controllers/main.rb +2 -0
- metadata +133 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Dan Glegg
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
|
4
|
+
require 'merb-core'
|
5
|
+
require 'merb-core/tasks/merb'
|
6
|
+
|
7
|
+
require 'spec/rake/spectask'
|
8
|
+
require 'merb-core/test/tasks/spectasks'
|
9
|
+
require 'merb_datamapper/merbtasks'
|
10
|
+
|
11
|
+
desc 'Default: run spec examples'
|
12
|
+
task :default => 'spec'
|
13
|
+
|
14
|
+
|
15
|
+
GEM_NAME = "ooh-auth"
|
16
|
+
AUTHOR = "Dan Glegg"
|
17
|
+
EMAIL = "dan@angryamoeba.co.uk"
|
18
|
+
HOMEPAGE = "http://github.com/danski/ooh-auth"
|
19
|
+
SUMMARY = "Merb Slice that provides RESTful authentication functionality for your application."
|
20
|
+
GEM_VERSION = "0.1.2"
|
21
|
+
|
22
|
+
spec = Gem::Specification.new do |s|
|
23
|
+
s.rubyforge_project = 'merb'
|
24
|
+
s.name = GEM_NAME
|
25
|
+
s.version = GEM_VERSION
|
26
|
+
s.platform = Gem::Platform::RUBY
|
27
|
+
s.has_rdoc = true
|
28
|
+
s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
|
29
|
+
s.summary = SUMMARY
|
30
|
+
s.description = s.summary
|
31
|
+
s.author = AUTHOR
|
32
|
+
s.email = EMAIL
|
33
|
+
s.homepage = HOMEPAGE
|
34
|
+
s.add_dependency('merb-slices', '>= 0.9.10')
|
35
|
+
s.require_path = 'lib'
|
36
|
+
s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec,app,public,stubs}/**/*")
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
40
|
+
pkg.gem_spec = spec
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Install the gem"
|
44
|
+
task :install do
|
45
|
+
Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Uninstall the gem"
|
49
|
+
task :uninstall do
|
50
|
+
Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Create a gemspec file"
|
54
|
+
task :gemspec do
|
55
|
+
File.open("#{GEM_NAME}.gemspec", "w") do |file|
|
56
|
+
file.puts spec.to_ruby
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class OohAuth::Application < Merb::Controller
|
2
|
+
|
3
|
+
controller_for_slice
|
4
|
+
|
5
|
+
private
|
6
|
+
def user_class
|
7
|
+
Merb::Authentication.user_class
|
8
|
+
end
|
9
|
+
|
10
|
+
# Can be removed once http://merb.lighthouseapp.com/projects/7433/tickets/956-patch-add-message-support
|
11
|
+
# is merged.
|
12
|
+
def message=(arg)
|
13
|
+
@_message = arg
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class OohAuth::AuthenticatingClients < OohAuth::Application
|
2
|
+
|
3
|
+
before :ensure_authenticated, :exclude=>[:index]
|
4
|
+
only_provides :html
|
5
|
+
|
6
|
+
def index
|
7
|
+
@authenticating_clients = OohAuth::AuthenticatingClient.find_for_user(session.user)
|
8
|
+
render :index
|
9
|
+
end
|
10
|
+
|
11
|
+
def show(id)
|
12
|
+
@authenticating_client = OohAuth::AuthenticatingClient.get(id)
|
13
|
+
raise NotFound unless @authenticating_client and @authenticating_client.editable_by?(session.user)
|
14
|
+
display @authenticating_client, :show
|
15
|
+
end
|
16
|
+
|
17
|
+
def new
|
18
|
+
@authenticating_client = OohAuth::AuthenticatingClient.new
|
19
|
+
display @authenticating_client
|
20
|
+
end
|
21
|
+
|
22
|
+
def create(authenticating_client)
|
23
|
+
@authenticating_client = OohAuth::AuthenticatingClient.new_for_user(session.user, authenticating_client)
|
24
|
+
if @authenticating_client.save
|
25
|
+
headers['Location'] = slice_url(:authenticating_client, @authenticating_client)
|
26
|
+
render :show, :status=>201
|
27
|
+
else
|
28
|
+
message[:error] = "There were problems creating the Application."
|
29
|
+
render :new
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def edit(id)
|
34
|
+
@authenticating_client = OohAuth::AuthenticatingClient.get(id)
|
35
|
+
raise NotFound unless @authenticating_client and @authenticating_client.editable_by?(session.user)
|
36
|
+
display @authenticating_client, :edit
|
37
|
+
end
|
38
|
+
|
39
|
+
def update(id, authenticating_client)
|
40
|
+
@authenticating_client = OohAuth::AuthenticatingClient.get(id)
|
41
|
+
raise NotFound unless @authenticating_client and @authenticating_client.editable_by?(session.user)
|
42
|
+
if @authenticating_client.update_attributes(authenticating_client)
|
43
|
+
message[:success] = "Application updated successfully!"
|
44
|
+
redirect slice_url(:authenticating_client, @authenticating_client)
|
45
|
+
else
|
46
|
+
display @authenticating_client, :edit
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def destroy(id)
|
51
|
+
@authenticating_client = OohAuth::AuthenticatingClient.get(id)
|
52
|
+
raise NotFound unless @authenticating_client and @authenticating_client.editable_by?(session.user)
|
53
|
+
if @authenticating_client.destroy
|
54
|
+
redirect slice_url(:authenticating_clients)
|
55
|
+
else
|
56
|
+
raise InternalServerError
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end # OohAuth::AuthenticatingClients
|
@@ -0,0 +1,94 @@
|
|
1
|
+
=begin
|
2
|
+
OohAuth::Tokens
|
3
|
+
|
4
|
+
This controller is intended to allow applications to authenticate on behalf of a user.
|
5
|
+
Applications follow a set process as shown in authenticating.markdown, in which a number of background
|
6
|
+
requests are made to the host application while the user is run through a short process in which they
|
7
|
+
specify which privileges to give to the authenticating client, and how long to give them for.
|
8
|
+
|
9
|
+
The Authentications controller provides a relatively opaque interface to
|
10
|
+
users and authenticating clients compared to other resource controllers. Most of the views provide only HTML
|
11
|
+
representations as they not only are intended for human interaction, but specifically require it.
|
12
|
+
=end
|
13
|
+
|
14
|
+
require 'net/http'
|
15
|
+
|
16
|
+
class OohAuth::Tokens < OohAuth::Application
|
17
|
+
|
18
|
+
# Define other formats
|
19
|
+
provides :js, :xml, :yaml
|
20
|
+
|
21
|
+
# The index and new actions require a signed request.
|
22
|
+
before :ensure_signed, :only=>[:index]
|
23
|
+
# All other actions require that the user be authenticated directly, rather than through the api.
|
24
|
+
before :forbid_authentication_with_oauth, :exclude=>[:index]
|
25
|
+
|
26
|
+
# Main action used for starting the authorisation process (desktop clients) and finishing it (web clients)
|
27
|
+
def index
|
28
|
+
raise NotAcceptable unless @authenticating_client = request.authenticating_client
|
29
|
+
if @token = request.authentication_token
|
30
|
+
# If client and request key, give the activated token if it was activated.
|
31
|
+
raise NotAcceptable unless @token.authenticating_client == @authenticating_client
|
32
|
+
else
|
33
|
+
# Generate a request key
|
34
|
+
@token = OohAuth::Token.create_request_key(@authenticating_client)
|
35
|
+
end
|
36
|
+
# # Okay, no error raised. Gogo render.
|
37
|
+
display @token, :show, :layout=>false
|
38
|
+
end
|
39
|
+
|
40
|
+
def new
|
41
|
+
only_provides :html
|
42
|
+
unless (@token = OohAuth::Token.first(:token_key=>request.token) and
|
43
|
+
@authenticating_client = @token.authenticating_client)
|
44
|
+
raise NotAcceptable
|
45
|
+
end
|
46
|
+
display @token, :new
|
47
|
+
end
|
48
|
+
|
49
|
+
# Activates an authentication receipt, converting it into a token the authenticating client can use in future requests.
|
50
|
+
def create(token)
|
51
|
+
only_provides :html
|
52
|
+
commit = (params[:commit]=="allow") # Did they click the allow or the deny button? ENQUIRING MINDS NEED TO KNOW!
|
53
|
+
raise NotFound unless @token = OohAuth::Token.get_token(request.token) # The oauth_token is now in the post body.
|
54
|
+
raise NotFound unless @authenticating_client = @token.authenticating_client # Stop right there, criminal scum.
|
55
|
+
|
56
|
+
@activated = @token.activate!(session.user, token[:expires], token[:permissions]) if commit
|
57
|
+
redirect("#{request.callback}#{(request.callback["?"])? "&" : "?"}oauth_token=#{@token.token_key}") if commit and request.callback # the callback is in the post body
|
58
|
+
display @token, :create
|
59
|
+
end
|
60
|
+
|
61
|
+
#def show(id)
|
62
|
+
# @token = ::Authentication.get(id)
|
63
|
+
# raise NotFound unless @token
|
64
|
+
# display @token
|
65
|
+
#end
|
66
|
+
#
|
67
|
+
#def edit(id)
|
68
|
+
# only_provides :html
|
69
|
+
# @token = OohAuth::Token.get(id)
|
70
|
+
# raise NotFound unless @token
|
71
|
+
# display @token
|
72
|
+
#end
|
73
|
+
#
|
74
|
+
#def update(id, token)
|
75
|
+
# @token = OohAuth::Token.get(id)
|
76
|
+
# raise NotFound unless @token
|
77
|
+
# if @token.update_attributes(authentication)
|
78
|
+
# redirect slice_url(:tokens, @token)
|
79
|
+
# else
|
80
|
+
# display @token, :edit
|
81
|
+
# end
|
82
|
+
#end
|
83
|
+
#
|
84
|
+
#def destroy(id)
|
85
|
+
# @token = OohAuth::Token.get(id)
|
86
|
+
# raise NotFound unless @token
|
87
|
+
# if @token.destroy
|
88
|
+
# redirect slice_url(:tokens)
|
89
|
+
# else
|
90
|
+
# raise InternalServerError
|
91
|
+
# end
|
92
|
+
#end
|
93
|
+
|
94
|
+
end # OohAuth::Tokens
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Merb
|
2
|
+
module OohAuth
|
3
|
+
module ApplicationHelper
|
4
|
+
|
5
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
6
|
+
#
|
7
|
+
# @return <String>
|
8
|
+
# A path relative to the public directory, with added segments.
|
9
|
+
def image_path(*segments)
|
10
|
+
public_path_for(:image, *segments)
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
14
|
+
#
|
15
|
+
# @return <String>
|
16
|
+
# A path relative to the public directory, with added segments.
|
17
|
+
def javascript_path(*segments)
|
18
|
+
public_path_for(:javascript, *segments)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
22
|
+
#
|
23
|
+
# @return <String>
|
24
|
+
# A path relative to the public directory, with added segments.
|
25
|
+
def stylesheet_path(*segments)
|
26
|
+
public_path_for(:stylesheet, *segments)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Construct a path relative to the public directory
|
30
|
+
#
|
31
|
+
# @param <Symbol> The type of component.
|
32
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
33
|
+
#
|
34
|
+
# @return <String>
|
35
|
+
# A path relative to the public directory, with added segments.
|
36
|
+
def public_path_for(type, *segments)
|
37
|
+
::OohAuth.public_path_for(type, *segments)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Construct an app-level path.
|
41
|
+
#
|
42
|
+
# @param <Symbol> The type of component.
|
43
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
44
|
+
#
|
45
|
+
# @return <String>
|
46
|
+
# A path within the host application, with added segments.
|
47
|
+
def app_path_for(type, *segments)
|
48
|
+
::OohAuth.app_path_for(type, *segments)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Construct a slice-level path.
|
52
|
+
#
|
53
|
+
# @param <Symbol> The type of component.
|
54
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
55
|
+
#
|
56
|
+
# @return <String>
|
57
|
+
# A path within the slice source (Gem), with added segments.
|
58
|
+
def slice_path_for(type, *segments)
|
59
|
+
::OohAuth.slice_path_for(type, *segments)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
path = File.expand_path(File.dirname(__FILE__)) / "authenticating_client"
|
2
|
+
if defined?(DataMapper)
|
3
|
+
require path / "dm_authenticating_client"
|
4
|
+
#elsif defined?(ActiveRecord)
|
5
|
+
# require path / "ar_password_reset"
|
6
|
+
#elsif defined?(Sequel)
|
7
|
+
# require path / "sq_password_reset"
|
8
|
+
#elsif defined?(RelaxDB)
|
9
|
+
# require path / "relaxdb_password_reset"
|
10
|
+
else
|
11
|
+
raise RuntimeError, "Datamapper is a dependency of the slice at this time."
|
12
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
=begin
|
2
|
+
OohAuth::AuthenticatingClient
|
3
|
+
========================================================================================
|
4
|
+
An authenticating client is an external application which wants to use your application's public API while authenticated as one of your users.
|
5
|
+
=end
|
6
|
+
|
7
|
+
class OohAuth::AuthenticatingClient
|
8
|
+
include DataMapper::Resource
|
9
|
+
|
10
|
+
# Key it
|
11
|
+
property :id, Serial
|
12
|
+
# The registration will belong to a user, who will be able to edit the client properties.
|
13
|
+
property :user_id, Integer, :writer => :protected
|
14
|
+
# Timestamp it
|
15
|
+
property :created_at, DateTime
|
16
|
+
|
17
|
+
# Used by all type of authenticating apps
|
18
|
+
property :name, String # e.g. "Mobilator PRO"
|
19
|
+
property :web_url, URI # e.g. "http://mobilator.portionator.net"
|
20
|
+
property :api_key, String, :index=>true # the unique key for this application.
|
21
|
+
property :secret, String # the secret which will NEVER be transmitted during the authentication procedure. Used only to sign requests.
|
22
|
+
property :kind, String # e.g "desktop", "web", "mobile"
|
23
|
+
|
24
|
+
validates_present :name, :web_url, :api_key, :secret, :kind
|
25
|
+
validates_is_unique :name
|
26
|
+
validates_is_unique :api_key
|
27
|
+
validates_with_method :kind, :valid_kind?
|
28
|
+
|
29
|
+
before :valid?, :generate_keys_if_not_present
|
30
|
+
|
31
|
+
def self.new_for_user(user, attrs)
|
32
|
+
o = new(attrs)
|
33
|
+
o.user = user
|
34
|
+
return o
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.find_for_user(user)
|
38
|
+
return [] unless user
|
39
|
+
return all(:user_id=>user.id)
|
40
|
+
end
|
41
|
+
|
42
|
+
def is_webapp?
|
43
|
+
self.kind == "web"
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_keys_if_not_present
|
47
|
+
api_key_length = 15
|
48
|
+
while self.api_key.blank? or self.class.first(:id.not=>id, :api_key=>self.api_key) do
|
49
|
+
self.api_key = OohAuth::KeyGenerators::Alphanum.gen(api_key_length)
|
50
|
+
api_key_length += 1
|
51
|
+
end
|
52
|
+
self.secret = OohAuth::KeyGenerators::Alphanum.gen(40) if secret.blank?
|
53
|
+
end
|
54
|
+
|
55
|
+
def valid_kind?
|
56
|
+
if OohAuth[:client_kinds].include?(self.kind)
|
57
|
+
return true
|
58
|
+
else
|
59
|
+
return false, "illegal kind"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def user=(user)
|
64
|
+
self.user_id = user.id
|
65
|
+
end
|
66
|
+
|
67
|
+
def editable_by?(user)
|
68
|
+
user.id == self.user_id
|
69
|
+
end
|
70
|
+
|
71
|
+
end # OohAuth::AuthenticatingClient
|
data/app/models/token.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
path = File.expand_path(File.dirname(__FILE__)) / "token"
|
2
|
+
if defined?(DataMapper)
|
3
|
+
require path / "dm_token"
|
4
|
+
#elsif defined?(ActiveRecord)
|
5
|
+
# require path / "ar_password_reset"
|
6
|
+
#elsif defined?(Sequel)
|
7
|
+
# require path / "sq_password_reset"
|
8
|
+
#elsif defined?(RelaxDB)
|
9
|
+
# require path / "relaxdb_password_reset"
|
10
|
+
else
|
11
|
+
raise RuntimeError, "Datamapper is a dependency of the slice at this time."
|
12
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
=begin
|
2
|
+
Token model
|
3
|
+
|
4
|
+
A token is a stored authorisation allowing an authenticating client to:
|
5
|
+
|
6
|
+
1. Get a *request key*. This is done by creating an unactivated token belonging to the authenticating client which has a _request key_.
|
7
|
+
2. *Request access*. This is done by directing the user to a URL unique to the given request key, presenting them with a form.
|
8
|
+
The user must be logged in through direct means in order to grant access.
|
9
|
+
3. Getting an *access key* which is a property of the now-activated token.
|
10
|
+
|
11
|
+
=end
|
12
|
+
|
13
|
+
class OohAuth::Token
|
14
|
+
include DataMapper::Resource
|
15
|
+
|
16
|
+
property :id, Serial
|
17
|
+
property :user_id, Integer, :writer=>:protected
|
18
|
+
property :authenticating_client_id, Integer, :writer=>:protected
|
19
|
+
|
20
|
+
# Expiry date will always be respected. You cannot authenticate using an expired token, and nor can you
|
21
|
+
# convert an expired request key into an access key.
|
22
|
+
property :expires, DateTime
|
23
|
+
property :created_at, DateTime
|
24
|
+
property :permissions, String
|
25
|
+
|
26
|
+
property :token_key, String, :writer=>:private, :index=>true
|
27
|
+
property :activated, Boolean, :writer=>:private, :index=>true, :default=>false
|
28
|
+
property :secret, String, :writer=>:private
|
29
|
+
|
30
|
+
validates_is_unique :token_key
|
31
|
+
validates_present :secret
|
32
|
+
validates_present :authenticating_client
|
33
|
+
validates_with_method :permissions, :permissions_valid?
|
34
|
+
|
35
|
+
belongs_to :authenticating_client, :class_name=>"OohAuth::AuthenticatingClient", :child_key=>[:authenticating_client_id]
|
36
|
+
belongs_to :user, :class_name=>Merb::Authentication.user_class.to_s, :child_key=>[:user_id]
|
37
|
+
|
38
|
+
before :valid?, :create_token_key_if_not_present
|
39
|
+
before :valid?, :create_secret_if_not_present
|
40
|
+
|
41
|
+
# Authenticates a client on behalf of a user given the API parameters sent by the client
|
42
|
+
# in the given API request. Returns the user on successful authentication, or false in
|
43
|
+
# the event of a failure to authenticate. If the user was since deleted, NIL will be
|
44
|
+
# returned.
|
45
|
+
def self.authenticate!(consumer_key, access_key)
|
46
|
+
auth = first('authenticating_client.api_key'=>consumer_key, :token_key=>access_key, :activated=>true, :expires.gt=>DateTime.now)
|
47
|
+
return (auth)? auth.user : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# FIXME the relationship helper should be sorting this. Something to do with the variable class.
|
51
|
+
def user
|
52
|
+
Merb::Authentication.user_class.get(user_id)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Tentatively create a request_key for a given client, not yet tied to a user.
|
56
|
+
def self.create_request_key(authenticating_client, expires=1.hour.since)
|
57
|
+
o = new(:authenticating_client=>authenticating_client, :expires=>expires)
|
58
|
+
o.save or raise RuntimeError, "OAuth request key failed to save with errors: #{o.errors.inspect}"
|
59
|
+
o
|
60
|
+
end
|
61
|
+
|
62
|
+
# Fetch a request_key given the request_key code
|
63
|
+
def self.get_request_key_for_client(client, request_key)
|
64
|
+
first :token_key=>request_key, :authenticating_client_id=>client.id, :expires.gt=>DateTime.now, :activated=>false
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.get_token(token)
|
68
|
+
first :token_key=>token
|
69
|
+
end
|
70
|
+
|
71
|
+
# Make this Authentication object active by generating an access key against it.
|
72
|
+
# You may optionally specify a new expiry date/time for the access key.
|
73
|
+
def activate!(with_user, expire_on=nil, permissions=nil)
|
74
|
+
if authenticating_client and with_user
|
75
|
+
self.activated = true
|
76
|
+
self.expires = (expire_on || 1.year.since)
|
77
|
+
self.permissions = (permissions || OohAuth[:default_permissions])
|
78
|
+
self.user_id = with_user.id
|
79
|
+
generate_token_key!
|
80
|
+
return save
|
81
|
+
else
|
82
|
+
return false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Checks to see if this Authentication is activated - if there is an access key defined, then
|
87
|
+
# true is returned.
|
88
|
+
#def activated?
|
89
|
+
# ac
|
90
|
+
#end
|
91
|
+
|
92
|
+
# Assigns a valid, unique request_key to the object if one is not already defined.
|
93
|
+
def create_token_key_if_not_present
|
94
|
+
generate_token_key! if token_key.blank?
|
95
|
+
end
|
96
|
+
|
97
|
+
def create_secret_if_not_present
|
98
|
+
self.secret ||= OohAuth::KeyGenerators::Alphanum.gen(30)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Generates a valid, unique access_key which the client can use to authenticate with in future,
|
102
|
+
# and applies it to the object.
|
103
|
+
def generate_token_key!
|
104
|
+
while (token_key.blank? or self.class.first(:token_key=>token_key)) do
|
105
|
+
self.token_key = OohAuth::KeyGenerators::Alphanum.gen(30)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns true if the given user is the owner of this object.
|
110
|
+
def editable_by_user?(user)
|
111
|
+
return user.id == user_id
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns the permissions for this particular token, or the :default_permissions if not set.
|
115
|
+
def permissions
|
116
|
+
attribute_get(:permissions) or OohAuth[:default_permissions]
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns true if the set permissions are a valid value according to the keys of the slice's :client_permission_levels hash.
|
120
|
+
def permissions_valid?
|
121
|
+
OohAuth[:client_permission_levels].keys.include?(permissions.to_sym)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Transformation - returns a hash representing this object, ready to be converted to XML, JSON or YAML.
|
125
|
+
def to_hash
|
126
|
+
if activated?
|
127
|
+
{
|
128
|
+
:access_key=>{
|
129
|
+
:token=>token_key,
|
130
|
+
:secret=>secret,
|
131
|
+
:expires=>expires
|
132
|
+
}
|
133
|
+
}
|
134
|
+
else
|
135
|
+
{
|
136
|
+
:request_key=>{
|
137
|
+
:token=>token_key,
|
138
|
+
:secret=>secret,
|
139
|
+
:expires=>expires
|
140
|
+
}
|
141
|
+
}
|
142
|
+
end
|
143
|
+
end
|
144
|
+
# FIXME why is to_xml not available?
|
145
|
+
def to_xml; (activated?)? "<access-key><token>#{token_key}</token><secret>#{secret}</secret><expires>#{expires}</expires></access-key>" : "<request-key><token>#{token_key}</token><secret>#{secret}</secret><expires>#{expires}</expires></request-key>"; end
|
146
|
+
def to_json; to_hash.to_json; end
|
147
|
+
def to_yaml; to_hash.to_yaml; end
|
148
|
+
|
149
|
+
|
150
|
+
end
|