aptible-auth 0.1.4 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: db3c1ba550b3a777611816a3828b182d0e2d3a27
4
- data.tar.gz: 97fe3444852024e2c306c40a85ac900179a4bfb1
3
+ metadata.gz: 9ead7f15f6ad01c4a7b9b7bed9a8840b07afe5c2
4
+ data.tar.gz: 34335f77ccea4353b373664ba3682d79c7fcbba1
5
5
  SHA512:
6
- metadata.gz: 2e106b93c20c79b736d18a7d7def5d381a1b6a956fce65c60acf06363f96d8ee336627e5d897bbe791be543900a1bc16e4a8d32c54cfcc1153c2a2a983d6b9c9
7
- data.tar.gz: af94ac3a6532389de1a5daece03a11aee35441189dcc77ba63e9f9aca11a1a6c54f967a54d4314c5481118e2f42206a9dfd9fac7a01ca171259f7f4518e32e16
6
+ metadata.gz: baa2716fc686c7adb7f45087b8ab63d0aadf82c8a392d5176a25d84cfc799e4d74660acc267e5e0d0cf146d058a810c7e31b816a5d3d5ebf345bc7f8ee680a04
7
+ data.tar.gz: 4f73fa2447498ebaf7ea19373fbfc592fd6c320f7ed0f587212e759d50c71d10a4169f2e04d81a2ad8c868641f965a41799edb4ef2a9ab1a4f6d8be105f56b78
@@ -0,0 +1 @@
1
+ console: bundle exec pry -r aptible/auth
data/README.md CHANGED
@@ -16,7 +16,7 @@ Add the following lines to your application's Gemfile.
16
16
 
17
17
  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.
18
18
 
19
- The forked version of the HyperResource gem is necessary until [gamache/hyperresource#19](https://github.com/gamache/hyperresource/pull/19) is merged.
19
+ The forked version of the HyperResource gem is necessary until [gamache/hyperresource#22](https://github.com/gamache/hyperresource/pull/22) and [gamache/hyperresource#23](https://github.com/gamache/hyperresource/pull/23) are merged.
20
20
 
21
21
  And then run `bundle install`.
22
22
 
@@ -28,9 +28,9 @@ First, get a token:
28
28
  token = Aptible::Auth::Token.new(email: 'user0@example.com', password: 'password')
29
29
  ```
30
30
 
31
- Then, initialize a client:
31
+ Then, initialize a resource agent:
32
32
  ```ruby
33
- auth = Aptible::Auth::Client.new(token: token)
33
+ auth = Aptible::Auth::Resource.new(token: token)
34
34
  ```
35
35
 
36
36
  From here, you can interact with the Authorization API however you wish:
@@ -3,11 +3,10 @@ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  require 'English'
6
- require 'aptible/auth/version'
7
6
 
8
7
  Gem::Specification.new do |spec|
9
8
  spec.name = 'aptible-auth'
10
- spec.version = Aptible::Auth::VERSION
9
+ spec.version = '0.2.0'
11
10
  spec.authors = ['Frank Macreery']
12
11
  spec.email = ['frank@macreery.com']
13
12
  spec.description = 'Ruby client for auth.aptible.com'
@@ -23,6 +22,7 @@ Gem::Specification.new do |spec|
23
22
  spec.add_dependency 'oauth2'
24
23
  spec.add_dependency 'hyperresource'
25
24
  spec.add_dependency 'fridge'
25
+ spec.add_dependency 'activesupport'
26
26
 
27
27
  spec.add_development_dependency 'bundler', '~> 1.3'
28
28
  spec.add_development_dependency 'aptible-tasks', '>= 0.2.0'
@@ -1,13 +1,13 @@
1
- require 'aptible/auth/version'
2
- require 'aptible/auth/token'
3
- require 'aptible/auth/client'
4
-
5
1
  require 'gem_config'
2
+ require 'hyperresource'
3
+ require 'fridge'
6
4
 
7
5
  module Aptible
8
- module Auth
6
+ class Auth < HyperResource
9
7
  include GemConfig::Base
10
8
 
9
+ attr_accessor :token, :config
10
+
11
11
  with_configuration do
12
12
  has :root_url,
13
13
  classes: [String],
@@ -15,7 +15,62 @@ module Aptible
15
15
  end
16
16
 
17
17
  def self.public_key
18
- Client.new.get.public_key
18
+ Resource.new.get.public_key
19
+ end
20
+
21
+ def self.get_data_type_from_response(response)
22
+ return nil unless response && response.body
23
+ adapter.get_data_type_from_object(adapter.deserialize(response.body))
24
+ end
25
+
26
+ def self.adapter
27
+ Aptible::Auth::Adapter
28
+ end
29
+
30
+ def adapter
31
+ self.class.adapter
32
+ end
33
+
34
+ def initialize(options = {})
35
+ if options.is_a?(Hash)
36
+ self.token = options[:token]
37
+
38
+ options[:root] ||= config.root_url
39
+ options[:namespace] ||= 'Aptible::Auth'
40
+ options[:headers] ||= { 'Content-Type' => 'application/json' }
41
+ options[:headers].merge!(
42
+ 'Authorization' => "Bearer #{bearer_token}"
43
+ ) if options[:token]
44
+ end
45
+
46
+ super(options)
47
+ end
48
+
49
+ def find_by_url(url)
50
+ fail "URL must be rooted at #{root}" unless /^#{root}/.match url
51
+
52
+ resource = dup
53
+ resource.href = url.gsub(/^#{root}/, '')
54
+ resource.get
55
+ end
56
+
57
+ def organizations
58
+ orgs
59
+ end
60
+
61
+ def bearer_token
62
+ case token
63
+ when Aptible::Auth::Token then token.access_token
64
+ when Fridge::AccessToken then token.to_s
65
+ when String then token
66
+ end
67
+ end
68
+
69
+ def config
70
+ @config ||= Aptible::Auth.configuration
19
71
  end
20
72
  end
21
73
  end
74
+
75
+ require 'aptible/auth/adapter'
76
+ require 'aptible/auth/resource'
@@ -0,0 +1,23 @@
1
+ module Aptible
2
+ class Auth::Adapter < HyperResource::Adapter::HAL_JSON
3
+ class << self
4
+ # rubocop:disable MethodLength
5
+ def get_data_type_from_object(object)
6
+ return nil unless object
7
+
8
+ if (type = object['type'])
9
+ if type == 'org'
10
+ 'Organization'
11
+ elsif type.respond_to?(:camelize)
12
+ type.camelize
13
+ else
14
+ type[0].upcase + type[1..-1]
15
+ end
16
+ else
17
+ 'Resource'
18
+ end
19
+ end
20
+ # rubocop:enable MethodLength
21
+ end
22
+ end
23
+ end
@@ -1,38 +1,4 @@
1
- require 'hyperresource'
2
- require 'fridge'
3
-
4
1
  module Aptible
5
- module Auth
6
- class Client < HyperResource
7
- attr_accessor :token, :config
8
-
9
- def initialize(options = {})
10
- unless options.is_a?(Hash)
11
- fail ArgumentError, 'Call Aptible::Auth::Client.new with a Hash'
12
- end
13
- self.token = options[:token]
14
-
15
- options[:root] ||= config.root_url
16
- options[:headers] ||= { 'Content-Type' => 'application/json' }
17
- options[:headers].merge!(
18
- 'Authorization' => "Bearer #{bearer_token}"
19
- ) if options[:token]
20
-
21
- super(options)
22
- end
23
-
24
- def bearer_token
25
- # REVIEW: Should we really allow any token type here?
26
- case token
27
- when Aptible::Auth::Token then token.access_token
28
- when Fridge::AccessToken then token.to_s
29
- when String then token
30
- end
31
- end
32
-
33
- def config
34
- @config ||= Aptible::Auth.configuration
35
- end
36
- end
2
+ class Auth::Client < Auth::Resource
37
3
  end
38
4
  end
@@ -0,0 +1,4 @@
1
+ module Aptible
2
+ class Auth::Membership < Auth::Resource
3
+ end
4
+ end
@@ -0,0 +1,15 @@
1
+ module Aptible
2
+ class Auth::Resource < Auth
3
+ def self.find_by_url(url)
4
+ # REVIEW: Should exception be raised if return type mismatch?
5
+ new.find_by_url(url)
6
+ end
7
+ end
8
+ end
9
+
10
+ require 'aptible/auth/client'
11
+ require 'aptible/auth/membership'
12
+ require 'aptible/auth/role'
13
+ require 'aptible/auth/session'
14
+ require 'aptible/auth/token'
15
+ require 'aptible/auth/user'
@@ -0,0 +1,4 @@
1
+ module Aptible
2
+ class Auth::Role < Auth::Resource
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Aptible
2
+ class Auth::Session < Auth::Resource
3
+ end
4
+ end
@@ -1,79 +1,78 @@
1
1
  require 'oauth2'
2
2
 
3
3
  module Aptible
4
- module Auth
5
- class Token
6
- attr_accessor :client, :access_token, :refresh_token, :expires_at
4
+ class Auth::Token < Auth::Resource
5
+ attr_accessor :access_token, :refresh_token, :expires_at
7
6
 
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
7
+ def self.create(options)
8
+ token = new
9
+ token.process_options(options)
10
+ token
11
+ end
17
12
 
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
13
+ def authenticate_user(email, password, options = {})
14
+ options[:scope] ||= 'manage'
15
+ response = oauth.password.get_token(email, password, options)
16
+ parse_oauth_response(response)
17
+ end
23
18
 
24
- def authenticate_client(id, secret, user, options = {})
25
- options[:scope] ||= 'manage'
26
- response = client.assertion.get_token({
27
- iss: id,
28
- sub: user
29
- }.merge(signing_params_from_secret(secret).merge(options)))
30
- parse_oauth_response(response)
31
- end
19
+ def authenticate_client(id, secret, subject, options = {})
20
+ options[:scope] ||= 'manage'
21
+ response = oauth.assertion.get_token({
22
+ iss: id,
23
+ sub: subject
24
+ }.merge(signing_params_from_secret(secret).merge(options)))
25
+ parse_oauth_response(response)
26
+ end
32
27
 
33
- private
28
+ def oauth
29
+ options = { site: config.root_url, token_url: '/tokens' }
30
+ @oauth ||= OAuth2::Client.new(nil, nil, options)
31
+ end
34
32
 
35
- def process_options(options)
36
- if (email = options.delete(:email)) &&
37
- (password = options.delete(:password))
38
- authenticate_user(email, password, options)
39
- elsif (client_id = options.delete(:client_id)) &&
40
- (client_secret = options.delete(:client_secret)) &&
41
- (user = options.delete(:user))
42
- authenticate_client(client_id, client_secret, user, options)
43
- end
33
+ def process_options(options)
34
+ if (email = options.delete(:email)) &&
35
+ (password = options.delete(:password))
36
+ authenticate_user(email, password, options)
37
+ elsif (client_id = options.delete(:client_id)) &&
38
+ (client_secret = options.delete(:client_secret)) &&
39
+ (subject = options.delete(:subject))
40
+ authenticate_client(client_id, client_secret, subject, options)
44
41
  end
42
+ end
45
43
 
46
- def parse_oauth_response(response)
47
- @access_token = response.token
48
- @refresh_token = response.refresh_token
49
- @expires_at = Time.at(response.expires_at)
50
- end
44
+ private
51
45
 
52
- def signing_params_from_secret(secret)
53
- private_key = parse_private_key(secret)
54
- {
55
- private_key: private_key,
56
- algorithm: "RS#{key_length(private_key) / 2}"
57
- }
58
- end
46
+ def parse_oauth_response(response)
47
+ @access_token = response.token
48
+ @refresh_token = response.refresh_token
49
+ @expires_at = Time.at(response.expires_at)
50
+ end
59
51
 
60
- def parse_private_key(string)
61
- if string =~ /\A-----/
62
- OpenSSL::PKey::RSA.new(string)
63
- else
64
- formatted_string = <<PRIVATE_KEY
65
- -----BEGIN RSA PRIVATE KEY-----
66
- #{string.scan(/.{1,64}/).join("\n")}
67
- -----END RSA PRIVATE KEY-----
68
- PRIVATE_KEY
69
- OpenSSL::PKey::RSA.new(formatted_string)
70
- end
71
- end
52
+ def signing_params_from_secret(secret)
53
+ private_key = parse_private_key(secret)
54
+ {
55
+ private_key: private_key,
56
+ algorithm: "RS#{key_length(private_key) / 2}"
57
+ }
58
+ end
72
59
 
73
- def key_length(private_key)
74
- # http://stackoverflow.com/questions/13747212
75
- private_key.n.num_bytes * 8
60
+ def parse_private_key(string)
61
+ if string =~ /\A-----/
62
+ OpenSSL::PKey::RSA.new(string)
63
+ else
64
+ formatted_string = <<-PRIVATE_KEY.gsub(/^\s+/, '')
65
+ -----BEGIN RSA PRIVATE KEY-----
66
+ #{string.scan(/.{1,64}/).join("\n")}
67
+ -----END RSA PRIVATE KEY-----
68
+ PRIVATE_KEY
69
+ OpenSSL::PKey::RSA.new(formatted_string)
76
70
  end
77
71
  end
72
+
73
+ def key_length(private_key)
74
+ # http://stackoverflow.com/questions/13747212
75
+ private_key.n.num_bytes * 8
76
+ end
78
77
  end
79
78
  end
@@ -0,0 +1,7 @@
1
+ module Aptible
2
+ class Auth::User < Auth::Resource
3
+ def verified?
4
+ !!attributes['verified']
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ # describe Aptible::Auth::Resource do
4
+ # end
@@ -1,32 +1,35 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Aptible::Auth::Token do
4
- let(:client) { double OAuth2::Client }
4
+ let(:oauth) { double OAuth2::Client }
5
5
  let(:response) { double OAuth2::AccessToken }
6
6
 
7
+ before { subject.stub(:oauth) { oauth } }
7
8
  before { response.stub(:token) }
8
9
  before { response.stub(:refresh_token) }
9
10
  before { response.stub(:expires_at) { Time.now.to_i } }
10
11
 
11
- describe '#initialize' do
12
+ describe '.create' do
12
13
  it 'should call #authenticate_user if passed :email and :password' do
13
14
  Aptible::Auth::Token.any_instance.should_receive(
14
15
  :authenticate_user
15
16
  ).with 'user@example.com', 'foobar', {}
16
- described_class.new(email: 'user@example.com', password: 'foobar')
17
+ described_class.create(email: 'user@example.com', password: 'foobar')
17
18
  end
18
19
 
19
20
  it 'should #authenticate_client if passed a client ID and secret' do
20
21
  Aptible::Auth::Token.any_instance.should_receive(
21
22
  :authenticate_client
22
23
  ).with 'id', 'secret', 'user@example.com', {}
23
- described_class.new(
24
+ described_class.create(
24
25
  client_id: 'id',
25
26
  client_secret: 'secret',
26
- user: 'user@example.com'
27
+ subject: 'user@example.com'
27
28
  )
28
29
  end
30
+ end
29
31
 
32
+ describe '#initialize' do
30
33
  it 'should not raise error if given no arguments' do
31
34
  expect { described_class.new }.not_to raise_error
32
35
  end
@@ -35,23 +38,22 @@ describe Aptible::Auth::Token do
35
38
  describe '#authenticate_user' do
36
39
  let(:args) { %w(user@example.com foobar) }
37
40
 
38
- before { subject.stub(:client) { client } }
39
- before { client.stub_chain(:password, :get_token) { response } }
41
+ before { oauth.stub_chain(:password, :get_token) { response } }
40
42
 
41
43
  it 'should use the password strategy' do
42
44
  params = { scope: 'manage' }
43
- expect(client.password).to receive(:get_token).with(*(args + [params]))
45
+ expect(oauth.password).to receive(:get_token).with(*(args + [params]))
44
46
  subject.authenticate_user(*args)
45
47
  end
46
48
 
47
49
  it 'should allow the token scope to be specified' do
48
50
  args << { scope: 'read' }
49
- expect(client.password).to receive(:get_token).with(*args)
51
+ expect(oauth.password).to receive(:get_token).with(*args)
50
52
  subject.authenticate_user(*args)
51
53
  end
52
54
 
53
55
  it 'should set the access_token' do
54
- client.stub_chain(:password, :get_token, :token) { 'access_token' }
56
+ oauth.stub_chain(:password, :get_token, :token) { 'access_token' }
55
57
  subject.authenticate_user(*args)
56
58
  expect(subject.access_token).to eq 'access_token'
57
59
  end
@@ -63,11 +65,10 @@ describe Aptible::Auth::Token do
63
65
  before do
64
66
  subject.stub(:signing_params_from_secret) { { algorithm: 'foobar' } }
65
67
  end
66
- before { subject.stub(:client) { client } }
67
- before { client.stub_chain(:assertion, :get_token) { response } }
68
+ before { oauth.stub_chain(:assertion, :get_token) { response } }
68
69
 
69
70
  it 'should use the assertion strategy' do
70
- expect(client.assertion).to receive(:get_token).with(
71
+ expect(oauth.assertion).to receive(:get_token).with(
71
72
  iss: 'id',
72
73
  sub: 'user@example.com',
73
74
  algorithm: 'foobar',
@@ -78,7 +79,7 @@ describe Aptible::Auth::Token do
78
79
 
79
80
  it 'should allow the token scope to be specified' do
80
81
  args << { scope: 'read' }
81
- expect(client.assertion).to receive(:get_token).with(
82
+ expect(oauth.assertion).to receive(:get_token).with(
82
83
  iss: 'id',
83
84
  sub: 'user@example.com',
84
85
  algorithm: 'foobar',
@@ -88,7 +89,7 @@ describe Aptible::Auth::Token do
88
89
  end
89
90
 
90
91
  it 'should set the access_token' do
91
- client.stub_chain(:assertion, :get_token, :token) { 'access_token' }
92
+ oauth.stub_chain(:assertion, :get_token, :token) { 'access_token' }
92
93
  subject.authenticate_client(*args)
93
94
  expect(subject.access_token).to eq 'access_token'
94
95
  end
@@ -17,8 +17,35 @@ describe Aptible::Auth do
17
17
 
18
18
  it 'should expose the server public key' do
19
19
  get = double 'get'
20
- Aptible::Auth::Client.any_instance.stub(:get) { get }
20
+ Aptible::Auth.any_instance.stub(:get) { get }
21
21
  expect(get).to receive :public_key
22
22
  described_class.public_key
23
23
  end
24
+
25
+ describe '#initialize' do
26
+ it 'should be a HyperResource instance' do
27
+ expect(subject).to be_a HyperResource
28
+ end
29
+ end
30
+
31
+ describe '#bearer_token' do
32
+ it 'should accept an Aptible::Auth::Token' do
33
+ token = Aptible::Auth::Token.new
34
+ token.stub(:access_token) { 'abtible_auth_token' }
35
+ subject.stub(:token) { token }
36
+ expect(subject.bearer_token).to eq token.access_token
37
+ end
38
+
39
+ it 'should accept an Fridge::AccessToken' do
40
+ token = Fridge::AccessToken.new
41
+ token.stub(:to_s) { 'fridge_access_token' }
42
+ subject.stub(:token) { token }
43
+ expect(subject.bearer_token).to eq token.to_s
44
+ end
45
+
46
+ it 'should accept a String' do
47
+ subject.stub(:token) { 'token' }
48
+ expect(subject.bearer_token).to eq 'token'
49
+ end
50
+ end
24
51
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aptible-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.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-02-19 00:00:00.000000000 Z
11
+ date: 2014-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_config
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -148,14 +162,20 @@ files:
148
162
  - .travis.yml
149
163
  - Gemfile
150
164
  - LICENSE.md
165
+ - Procfile
151
166
  - README.md
152
167
  - Rakefile
153
168
  - aptible-auth.gemspec
154
169
  - lib/aptible/auth.rb
170
+ - lib/aptible/auth/adapter.rb
155
171
  - lib/aptible/auth/client.rb
172
+ - lib/aptible/auth/membership.rb
173
+ - lib/aptible/auth/resource.rb
174
+ - lib/aptible/auth/role.rb
175
+ - lib/aptible/auth/session.rb
156
176
  - lib/aptible/auth/token.rb
157
- - lib/aptible/auth/version.rb
158
- - spec/aptible/auth/client_spec.rb
177
+ - lib/aptible/auth/user.rb
178
+ - spec/aptible/auth/resource_spec.rb
159
179
  - spec/aptible/auth/token_spec.rb
160
180
  - spec/aptible/auth_spec.rb
161
181
  - spec/shared/set_env.rb
@@ -185,7 +205,7 @@ signing_key:
185
205
  specification_version: 4
186
206
  summary: Ruby client for auth.aptible.com
187
207
  test_files:
188
- - spec/aptible/auth/client_spec.rb
208
+ - spec/aptible/auth/resource_spec.rb
189
209
  - spec/aptible/auth/token_spec.rb
190
210
  - spec/aptible/auth_spec.rb
191
211
  - spec/shared/set_env.rb
@@ -1,5 +0,0 @@
1
- module Aptible
2
- module Auth
3
- VERSION = '0.1.4'
4
- end
5
- end
@@ -1,30 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Aptible::Auth::Client do
4
- describe '#initialize' do
5
- it 'should be a HyperResource instance' do
6
- expect(subject).to be_a HyperResource
7
- end
8
- end
9
-
10
- describe '#bearer_token' do
11
- it 'should accept an Aptible::Auth::Token' do
12
- token = Aptible::Auth::Token.new
13
- token.stub(:access_token) { 'abtible_auth_token' }
14
- subject.stub(:token) { token }
15
- expect(subject.bearer_token).to eq token.access_token
16
- end
17
-
18
- it 'should accept an Fridge::AccessToken' do
19
- token = Fridge::AccessToken.new
20
- token.stub(:to_s) { 'fridge_access_token' }
21
- subject.stub(:token) { token }
22
- expect(subject.bearer_token).to eq token.to_s
23
- end
24
-
25
- it 'should accept a String' do
26
- subject.stub(:token) { 'token' }
27
- expect(subject.bearer_token).to eq 'token'
28
- end
29
- end
30
- end