aptible-auth 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +42 -5
- data/aptible-auth.gemspec +4 -1
- data/lib/aptible/auth.rb +12 -1
- data/lib/aptible/auth/client.rb +21 -6
- data/lib/aptible/auth/token.rb +50 -0
- data/lib/aptible/auth/version.rb +1 -1
- data/spec/aptible/auth/client_spec.rb +5 -1
- data/spec/aptible/auth/token_spec.rb +84 -0
- data/spec/aptible/auth_spec.rb +16 -0
- metadata +51 -7
- data/lib/aptible/auth/strategy/pubkey.rb +0 -25
- data/spec/aptible/auth/strategy/pubkey_spec.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 101f4e5eba0e9ddacf579ed8758ebbbdfba30d84
|
4
|
+
data.tar.gz: b2daa6d3703e05bfcba62c36d7469890430a7463
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 535418028b5197789fb200a8608133df28e5f2c6622d7a9d614c259409850139231209988a633a592fc6ef45e6808ecd8012ba1bea42223220b55e99df4280c8
|
7
|
+
data.tar.gz: c784ba5e1f430fd0ee88de2dc06a13214d7b0f4aab0c5ef57055fcd447dc4c56a69e02312f1293ff17612b179894c6b53ad8e734bd4a5c099d1a31fc9eae6c42
|
data/README.md
CHANGED
@@ -4,21 +4,58 @@
|
|
4
4
|
[![Build Status](https://travis-ci.org/aptible/aptible-auth-ruby.png?branch=master)](https://travis-ci.org/aptible/aptible-auth-ruby)
|
5
5
|
[![Dependency Status](https://gemnasium.com/aptible/aptible-auth-ruby.png)](https://gemnasium.com/aptible/aptible-auth-ruby)
|
6
6
|
|
7
|
-
Ruby client for [auth.aptible.com](https://auth.aptible.com/).
|
8
|
-
|
9
|
-
However, due to the complexity of OAuth 2.0 and the fact that it is a fragmented and evolving standard, we provide this gem as a standard Ruby client library. All of our internal services use it, and so it can be expected to work.
|
7
|
+
Ruby client for [auth.aptible.com](https://auth.aptible.com/). Aptible's authorization server is built on top of [OAuth 2.0](http://tools.ietf.org/html/rfc6749) and [HAL+JSON](http://tools.ietf.org/html/draft-kelly-json-hal-06), and so this client is just a thin layer on top of the [oauth2](https://github.com/intridea/oauth2) and [HyperResource](https://github.com/gamache/hyperresource) gems.
|
10
8
|
|
11
9
|
## Installation
|
12
10
|
|
13
|
-
Add the following
|
11
|
+
Add the following lines to your application's Gemfile.
|
14
12
|
|
15
13
|
gem 'aptible-auth'
|
14
|
+
gem 'oauth2', github: 'fancyremarker/oauth2', branch: 'aptible'
|
15
|
+
|
16
|
+
The forked version of the OAuth2 gem is necessary until [intridea/oauth2#165](https://github.com/intridea/oauth2/pull/165) and [intridea/oauth2#166](https://github.com/intridea/oauth2/pull/166) are merged.
|
16
17
|
|
17
18
|
And then run `bundle install`.
|
18
19
|
|
19
20
|
## Usage
|
20
21
|
|
21
|
-
|
22
|
+
First, get a token:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
token = Aptible::Auth::Token.new(email: 'user0@example.com', password: 'password')
|
26
|
+
```
|
27
|
+
|
28
|
+
Then, initialize a client:
|
29
|
+
```ruby
|
30
|
+
auth = Aptible::Auth::Client.new(token: token)
|
31
|
+
```
|
32
|
+
|
33
|
+
From here, you can interact with the Authorization API however you wish:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
auth.get
|
37
|
+
auth.clients.count
|
38
|
+
# => 4
|
39
|
+
auth.clients.first.name
|
40
|
+
# => "Client 0"
|
41
|
+
client = auth.clients.create(name: 'Dogeclient')
|
42
|
+
client.href
|
43
|
+
# => "http://localhost:4000/clients/60765b69-ffd8-4762-b9d2-96354ddb16f9"
|
44
|
+
```
|
45
|
+
|
46
|
+
## Configuration
|
47
|
+
|
48
|
+
| Parameter | Description | Default |
|
49
|
+
| --------- | ----------- | --------------- |
|
50
|
+
| `root_url` | Root URL of the authorization server | `https://auth.aptible.com` |
|
51
|
+
|
52
|
+
To point the client at a different authorization server (e.g., during development), add the following to your application's initializers:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
Aptible::Auth.configure do |config|
|
56
|
+
config.root_url = 'http://some.other.url'
|
57
|
+
end
|
58
|
+
```
|
22
59
|
|
23
60
|
## Contributing
|
24
61
|
|
data/aptible-auth.gemspec
CHANGED
@@ -19,10 +19,13 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(/^spec\//)
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
|
+
spec.add_dependency 'gem_config'
|
22
23
|
spec.add_dependency 'oauth2'
|
24
|
+
spec.add_dependency 'hyperresource'
|
23
25
|
|
24
26
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
25
27
|
spec.add_development_dependency 'aptible-tasks', '>= 0.2.0'
|
26
28
|
spec.add_development_dependency 'rake'
|
27
|
-
spec.
|
29
|
+
spec.add_development_dependency 'rspec', '~> 2.0'
|
30
|
+
spec.add_development_dependency 'pry'
|
28
31
|
end
|
data/lib/aptible/auth.rb
CHANGED
@@ -1,8 +1,19 @@
|
|
1
1
|
require 'aptible/auth/version'
|
2
|
+
require 'aptible/auth/token'
|
2
3
|
require 'aptible/auth/client'
|
3
4
|
|
5
|
+
require 'gem_config'
|
6
|
+
|
4
7
|
module Aptible
|
5
8
|
module Auth
|
6
|
-
|
9
|
+
include GemConfig::Base
|
10
|
+
|
11
|
+
with_configuration do
|
12
|
+
has :root_url, classes: [String], default: 'https://auth.aptible.com'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.public_key
|
16
|
+
Client.new.get.public_key
|
17
|
+
end
|
7
18
|
end
|
8
19
|
end
|
data/lib/aptible/auth/client.rb
CHANGED
@@ -1,12 +1,27 @@
|
|
1
|
-
require '
|
2
|
-
require 'aptible/auth/strategy/pubkey'
|
1
|
+
require 'hyperresource'
|
3
2
|
|
4
3
|
module Aptible
|
5
4
|
module Auth
|
6
|
-
class Client <
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
class Client < HyperResource
|
6
|
+
attr_accessor :token, :config
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
unless options.is_a?(Hash)
|
10
|
+
fail ArgumentError, 'Call Aptible::Auth::Client.new with a Hash'
|
11
|
+
end
|
12
|
+
@token = options[:token]
|
13
|
+
|
14
|
+
options[:root] ||= config.root_url
|
15
|
+
options[:headers] ||= { 'Content-Type' => 'application/json' }
|
16
|
+
options[:headers].merge!(
|
17
|
+
'Authorization' => "Bearer #{options[:token].access_token}"
|
18
|
+
) if options[:token]
|
19
|
+
|
20
|
+
super(options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def config
|
24
|
+
@config ||= Aptible::Auth.configuration
|
10
25
|
end
|
11
26
|
end
|
12
27
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
|
3
|
+
module Aptible
|
4
|
+
module Auth
|
5
|
+
class Token
|
6
|
+
attr_accessor :client, :access_token, :refresh_token, :expires_at
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
oauth_params = {
|
10
|
+
site: Aptible::Auth.configuration.root_url,
|
11
|
+
token_url: '/tokens'
|
12
|
+
}
|
13
|
+
@client = OAuth2::Client.new(nil, nil, oauth_params)
|
14
|
+
|
15
|
+
process_options(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def authenticate_user(email, password, options = {})
|
19
|
+
options[:scope] ||= 'manage'
|
20
|
+
response = client.password.get_token(email, password, options)
|
21
|
+
parse_oauth_response(response)
|
22
|
+
end
|
23
|
+
|
24
|
+
def authenticate_client(id, secret, user, options = {})
|
25
|
+
options[:scope] ||= 'manage'
|
26
|
+
response = client.assertion.get_token(id, secret, user, options)
|
27
|
+
parse_oauth_response(response)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def process_options(options)
|
33
|
+
if (email = options.delete(:email)) &&
|
34
|
+
(password = options.delete(:password))
|
35
|
+
authenticate_user(email, password, options)
|
36
|
+
elsif (client_id = options.delete(:client_id)) &&
|
37
|
+
(client_secret = options.delete(:client_secret)) &&
|
38
|
+
(user = options.delete(:user))
|
39
|
+
authenticate_client(client_id, client_secret, user, options)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_oauth_response(response)
|
44
|
+
@access_token = response.token
|
45
|
+
@refresh_token = response.refresh_token
|
46
|
+
@expires_at = Time.at(response.expires_at)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/aptible/auth/version.rb
CHANGED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Aptible::Auth::Token do
|
4
|
+
let(:client) { double OAuth2::Client }
|
5
|
+
let(:response) { double OAuth2::AccessToken }
|
6
|
+
|
7
|
+
before { response.stub(:token) }
|
8
|
+
before { response.stub(:refresh_token) }
|
9
|
+
before { response.stub(:expires_at) { Time.now.to_i } }
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
it 'should call #authenticate_user if passed :email and :password' do
|
13
|
+
Aptible::Auth::Token.any_instance.should_receive(
|
14
|
+
:authenticate_user
|
15
|
+
).with 'user@example.com', 'foobar', {}
|
16
|
+
described_class.new(email: 'user@example.com', password: 'foobar')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should #authenticate_client if passed a client ID and secret' do
|
20
|
+
Aptible::Auth::Token.any_instance.should_receive(
|
21
|
+
:authenticate_client
|
22
|
+
).with 'id', 'secret', 'user@example.com', {}
|
23
|
+
described_class.new(
|
24
|
+
client_id: 'id',
|
25
|
+
client_secret: 'secret',
|
26
|
+
user: 'user@example.com'
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should not raise error if given no arguments' do
|
31
|
+
expect { described_class.new }.not_to raise_error
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#authenticate_user' do
|
36
|
+
let(:args) { %w(user@example.com foobar) }
|
37
|
+
|
38
|
+
before { subject.stub(:client) { client } }
|
39
|
+
before { client.stub_chain(:password, :get_token) { response } }
|
40
|
+
|
41
|
+
it 'should use the password strategy' do
|
42
|
+
params = { scope: 'manage' }
|
43
|
+
expect(client.password).to receive(:get_token).with(*(args + [params]))
|
44
|
+
subject.authenticate_user(*args)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should allow the token scope to be specified' do
|
48
|
+
args << { scope: 'read' }
|
49
|
+
expect(client.password).to receive(:get_token).with(*args)
|
50
|
+
subject.authenticate_user(*args)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should set the access_token' do
|
54
|
+
client.stub_chain(:password, :get_token, :token) { 'access_token' }
|
55
|
+
subject.authenticate_user(*args)
|
56
|
+
expect(subject.access_token).to eq 'access_token'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#authenticate_client' do
|
61
|
+
let(:args) { %w(id secret user@example.com) }
|
62
|
+
|
63
|
+
before { subject.stub(:client) { client } }
|
64
|
+
before { client.stub_chain(:assertion, :get_token) { response } }
|
65
|
+
|
66
|
+
it 'should use the assertion strategy' do
|
67
|
+
params = { scope: 'manage' }
|
68
|
+
expect(client.assertion).to receive(:get_token).with(*(args + [params]))
|
69
|
+
subject.authenticate_client(*args)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should allow the token scope to be specified' do
|
73
|
+
args << { scope: 'read' }
|
74
|
+
expect(client.assertion).to receive(:get_token).with(*args)
|
75
|
+
subject.authenticate_client(*args)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should set the access_token' do
|
79
|
+
client.stub_chain(:assertion, :get_token, :token) { 'access_token' }
|
80
|
+
subject.authenticate_client(*args)
|
81
|
+
expect(subject.access_token).to eq 'access_token'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Aptible::Auth do
|
4
|
+
it 'should have a configurable root_url' do
|
5
|
+
config = described_class.configuration
|
6
|
+
expect(config).to be_a GemConfig::Configuration
|
7
|
+
expect(config.root_url).to eq 'https://auth.aptible.com'
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should expose the server public key' do
|
11
|
+
get = double 'get'
|
12
|
+
Aptible::Auth::Client.any_instance.stub(:get) { get }
|
13
|
+
expect(get).to receive :public_key
|
14
|
+
described_class.public_key
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aptible-auth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frank Macreery
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gem_config
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: oauth2
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -24,6 +38,20 @@ dependencies:
|
|
24
38
|
- - '>='
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: hyperresource
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: bundler
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,13 +101,27 @@ dependencies:
|
|
73
101
|
- - ~>
|
74
102
|
- !ruby/object:Gem::Version
|
75
103
|
version: '2.0'
|
76
|
-
type: :
|
104
|
+
type: :development
|
77
105
|
prerelease: false
|
78
106
|
version_requirements: !ruby/object:Gem::Requirement
|
79
107
|
requirements:
|
80
108
|
- - ~>
|
81
109
|
- !ruby/object:Gem::Version
|
82
110
|
version: '2.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
83
125
|
description: Ruby client for auth.aptible.com
|
84
126
|
email:
|
85
127
|
- frank@macreery.com
|
@@ -97,10 +139,11 @@ files:
|
|
97
139
|
- aptible-auth.gemspec
|
98
140
|
- lib/aptible/auth.rb
|
99
141
|
- lib/aptible/auth/client.rb
|
100
|
-
- lib/aptible/auth/
|
142
|
+
- lib/aptible/auth/token.rb
|
101
143
|
- lib/aptible/auth/version.rb
|
102
144
|
- spec/aptible/auth/client_spec.rb
|
103
|
-
- spec/aptible/auth/
|
145
|
+
- spec/aptible/auth/token_spec.rb
|
146
|
+
- spec/aptible/auth_spec.rb
|
104
147
|
- spec/spec_helper.rb
|
105
148
|
homepage: https://github.com/aptible/aptible-auth
|
106
149
|
licenses:
|
@@ -122,11 +165,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
165
|
version: '0'
|
123
166
|
requirements: []
|
124
167
|
rubyforge_project:
|
125
|
-
rubygems_version: 2.
|
168
|
+
rubygems_version: 2.2.1
|
126
169
|
signing_key:
|
127
170
|
specification_version: 4
|
128
171
|
summary: Ruby client for auth.aptible.com
|
129
172
|
test_files:
|
130
173
|
- spec/aptible/auth/client_spec.rb
|
131
|
-
- spec/aptible/auth/
|
174
|
+
- spec/aptible/auth/token_spec.rb
|
175
|
+
- spec/aptible/auth_spec.rb
|
132
176
|
- spec/spec_helper.rb
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'oauth2'
|
2
|
-
|
3
|
-
module Aptible
|
4
|
-
module Auth
|
5
|
-
module Strategy
|
6
|
-
# The Pubkey Strategy (Aptible-custom)
|
7
|
-
class Pubkey < OAuth2::Strategy::Base
|
8
|
-
# TODO: Implement
|
9
|
-
#
|
10
|
-
# @raise [NotImplementedError]
|
11
|
-
def get_token(fingerprint, params = {}, opts = {})
|
12
|
-
# rubocop:disable UselessAssignment
|
13
|
-
params = {
|
14
|
-
'grant_type' => 'pubkey',
|
15
|
-
'fingerprint' => fingerprint,
|
16
|
-
'password' => password
|
17
|
-
}.merge(client_params).merge(params)
|
18
|
-
# rubocop:enable UselessAssignment
|
19
|
-
|
20
|
-
fail NotImplementedError, 'Strategy not yet implemented'
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|