minty 1.0.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 +7 -0
- data/.bundle/config +4 -0
- data/.devcontainer/Dockerfile +19 -0
- data/.devcontainer/devcontainer.json +37 -0
- data/.env.example +2 -0
- data/.gemrelease +2 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +33 -0
- data/.github/dependabot.yml +10 -0
- data/.github/stale.yml +20 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/.rubocop.yml +9 -0
- data/CODE_OF_CONDUCT.md +3 -0
- data/DEPLOYMENT.md +61 -0
- data/DEVELOPMENT.md +35 -0
- data/Dockerfile +5 -0
- data/EXAMPLES.md +195 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +250 -0
- data/Guardfile +39 -0
- data/LICENSE +21 -0
- data/Makefile +5 -0
- data/README.md +88 -0
- data/RUBYGEM.md +9 -0
- data/Rakefile +33 -0
- data/codecov.yml +22 -0
- data/lib/minty/algorithm.rb +7 -0
- data/lib/minty/api/authentication_endpoints.rb +30 -0
- data/lib/minty/api/v2.rb +8 -0
- data/lib/minty/client.rb +7 -0
- data/lib/minty/exception.rb +50 -0
- data/lib/minty/mixins/api_token_struct.rb +4 -0
- data/lib/minty/mixins/headers.rb +19 -0
- data/lib/minty/mixins/httpproxy.rb +125 -0
- data/lib/minty/mixins/initializer.rb +38 -0
- data/lib/minty/mixins/validation.rb +113 -0
- data/lib/minty/mixins.rb +23 -0
- data/lib/minty/version.rb +5 -0
- data/lib/minty.rb +11 -0
- data/lib/minty_client.rb +4 -0
- data/minty.gemspec +39 -0
- data/publish_rubygem.sh +10 -0
- data/spec/integration/lib/minty/api/api_authentication_spec.rb +122 -0
- data/spec/integration/lib/minty/minty_client_spec.rb +92 -0
- data/spec/lib/minty/client_spec.rb +223 -0
- data/spec/lib/minty/mixins/httpproxy_spec.rb +658 -0
- data/spec/lib/minty/mixins/initializer_spec.rb +121 -0
- data/spec/lib/minty/mixins/token_management_spec.rb +129 -0
- data/spec/lib/minty/mixins/validation_spec.rb +559 -0
- data/spec/spec_helper.rb +75 -0
- data/spec/support/credentials.rb +14 -0
- data/spec/support/dummy_class.rb +20 -0
- data/spec/support/dummy_class_for_proxy.rb +6 -0
- data/spec/support/dummy_class_for_restclient.rb +4 -0
- data/spec/support/dummy_class_for_tokens.rb +18 -0
- data/spec/support/import_users.json +13 -0
- data/spec/support/stub_response.rb +3 -0
- metadata +366 -0
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'addressable/uri'
|
4
|
+
require 'retryable'
|
5
|
+
require_relative '../exception'
|
6
|
+
|
7
|
+
module Minty
|
8
|
+
module Mixins
|
9
|
+
module HTTPProxy
|
10
|
+
attr_accessor :headers, :base_uri, :timeout, :retry_count
|
11
|
+
|
12
|
+
DEFAULT_RETRIES = 3
|
13
|
+
MAX_ALLOWED_RETRIES = 10
|
14
|
+
MAX_REQUEST_RETRY_JITTER = 250
|
15
|
+
MAX_REQUEST_RETRY_DELAY = 1000
|
16
|
+
MIN_REQUEST_RETRY_DELAY = 250
|
17
|
+
BASE_DELAY = 100
|
18
|
+
|
19
|
+
%i[get post post_file put patch delete delete_with_body].each do |method|
|
20
|
+
define_method(method) do |uri, body = {}, extra_headers = {}|
|
21
|
+
body = body.delete_if { |_, v| v.nil? }
|
22
|
+
token = get_token
|
23
|
+
authorization_header(token) unless token.nil?
|
24
|
+
request_with_retry(method, uri, body, extra_headers)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def retry_options
|
29
|
+
sleep_timer = lambda do |attempt|
|
30
|
+
wait = BASE_DELAY * (2**attempt - 1)
|
31
|
+
wait += rand(wait + 1..wait + MAX_REQUEST_RETRY_JITTER)
|
32
|
+
wait = [MAX_REQUEST_RETRY_DELAY, wait].min
|
33
|
+
wait = [MIN_REQUEST_RETRY_DELAY, wait].max
|
34
|
+
wait / 1000.to_f.round(2)
|
35
|
+
end
|
36
|
+
|
37
|
+
tries = 1 + [Integer(retry_count || DEFAULT_RETRIES), MAX_ALLOWED_RETRIES].min
|
38
|
+
|
39
|
+
{
|
40
|
+
tries: tries,
|
41
|
+
sleep: sleep_timer,
|
42
|
+
on: Minty::RateLimitEncountered
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def encode_uri(uri)
|
47
|
+
path = base_uri ? Addressable::URI.new(path: uri).normalized_path : Addressable::URI.escape(uri)
|
48
|
+
url(path)
|
49
|
+
end
|
50
|
+
|
51
|
+
def url(path)
|
52
|
+
"#{base_uri}#{path}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_headers(h = {})
|
56
|
+
raise ArgumentError, 'Headers must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
|
57
|
+
|
58
|
+
@headers ||= {}
|
59
|
+
@headers.merge!(h.to_hash)
|
60
|
+
end
|
61
|
+
|
62
|
+
def safe_parse_json(body)
|
63
|
+
JSON.parse(body.to_s)
|
64
|
+
rescue JSON::ParserError
|
65
|
+
body
|
66
|
+
end
|
67
|
+
|
68
|
+
def request_with_retry(method, uri, body = {}, extra_headers = {})
|
69
|
+
Retryable.retryable(retry_options) do
|
70
|
+
request(method, uri, body, extra_headers)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def request(method, uri, body = {}, extra_headers = {})
|
75
|
+
result = case method
|
76
|
+
when :get
|
77
|
+
@headers ||= {}
|
78
|
+
get_headers = @headers.merge({ params: body }).merge(extra_headers)
|
79
|
+
call(:get, encode_uri(uri), timeout, get_headers)
|
80
|
+
when :delete
|
81
|
+
@headers ||= {}
|
82
|
+
delete_headers = @headers.merge({ params: body })
|
83
|
+
call(:delete, encode_uri(uri), timeout, delete_headers)
|
84
|
+
when :delete_with_body
|
85
|
+
call(:delete, encode_uri(uri), timeout, headers, body.to_json)
|
86
|
+
when :post_file
|
87
|
+
body.merge!(multipart: true)
|
88
|
+
post_file_headers = headers.slice(*headers.keys - ['Content-Type'])
|
89
|
+
call(:post, encode_uri(uri), timeout, post_file_headers, body)
|
90
|
+
else
|
91
|
+
call(method, encode_uri(uri), timeout, headers, body.to_json)
|
92
|
+
end
|
93
|
+
|
94
|
+
case result.code
|
95
|
+
when 200...226 then safe_parse_json(result.body)
|
96
|
+
when 400 then raise Minty::BadRequest.new(result.body, code: result.code, headers: result.headers)
|
97
|
+
when 401 then raise Minty::Unauthorized.new(result.body, code: result.code, headers: result.headers)
|
98
|
+
when 403 then raise Minty::AccessDenied.new(result.body, code: result.code, headers: result.headers)
|
99
|
+
when 404 then raise Minty::NotFound.new(result.body, code: result.code, headers: result.headers)
|
100
|
+
when 429 then raise Minty::RateLimitEncountered.new(result.body, code: result.code,
|
101
|
+
headers: result.headers)
|
102
|
+
when 500 then raise Minty::ServerError.new(result.body, code: result.code, headers: result.headers)
|
103
|
+
else raise Minty::Unsupported.new(result.body, code: result.code, headers: result.headers)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def call(method, url, timeout, headers, body = nil)
|
108
|
+
RestClient::Request.execute(
|
109
|
+
method: method,
|
110
|
+
url: url,
|
111
|
+
timeout: timeout,
|
112
|
+
headers: headers,
|
113
|
+
payload: body
|
114
|
+
)
|
115
|
+
rescue RestClient::Exception => e
|
116
|
+
case e
|
117
|
+
when RestClient::RequestTimeout
|
118
|
+
raise Minty::RequestTimeout, e.message
|
119
|
+
else
|
120
|
+
e.response
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Minty
|
6
|
+
module Mixins
|
7
|
+
module Initializer
|
8
|
+
def initialize(config)
|
9
|
+
options = Hash[config.map { |(k, v)| [k.to_sym, v] }]
|
10
|
+
|
11
|
+
@base_uri = base_url(options)
|
12
|
+
@timeout = options[:timeout] || 10
|
13
|
+
@retry_count = options[:retry_count]
|
14
|
+
|
15
|
+
extend Minty::Api::AuthenticationEndpoints
|
16
|
+
|
17
|
+
@client_id = options[:client_id]
|
18
|
+
@client_secret = options[:client_secret]
|
19
|
+
@application_id = options[:application_id]
|
20
|
+
@organization = options[:organization]
|
21
|
+
@headers = client_headers(@client_id, @client_secret, @application_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.included(klass)
|
25
|
+
klass.send :prepend, Initializer
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def base_url(options)
|
31
|
+
@domain = options[:domain] || options[:namespace]
|
32
|
+
raise InvalidApiNamespace, 'API namespace must supply an API domain' if @domain.to_s.empty?
|
33
|
+
|
34
|
+
"https://#{@domain}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zache'
|
4
|
+
|
5
|
+
class Zache
|
6
|
+
def last(key)
|
7
|
+
@hash[key][:value] if @hash.key?(key)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module Minty
|
12
|
+
module Mixins
|
13
|
+
module Validation
|
14
|
+
class JWTAlgorithm
|
15
|
+
private_class_method :new
|
16
|
+
|
17
|
+
def name
|
18
|
+
raise 'Must be overriden by the subclasses'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Algorithm
|
23
|
+
class HS256 < JWTAlgorithm
|
24
|
+
class << self
|
25
|
+
private :new
|
26
|
+
|
27
|
+
def secret(secret)
|
28
|
+
new secret
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_accessor :secret
|
33
|
+
|
34
|
+
def initialize(secret)
|
35
|
+
raise Minty::InvalidParameter, 'Must supply a valid secret' if secret.to_s.empty?
|
36
|
+
|
37
|
+
@secret = secret
|
38
|
+
end
|
39
|
+
|
40
|
+
def name
|
41
|
+
'HS256'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class RS256 < JWTAlgorithm
|
46
|
+
include Minty::Mixins::HTTPProxy
|
47
|
+
|
48
|
+
@@cache = Zache.new.freeze
|
49
|
+
|
50
|
+
class << self
|
51
|
+
private :new
|
52
|
+
|
53
|
+
def jwks_url(url, lifetime: 10 * 60)
|
54
|
+
new url, lifetime
|
55
|
+
end
|
56
|
+
|
57
|
+
def remove_jwks
|
58
|
+
@@cache.remove_by { true }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize(jwks_url, lifetime)
|
63
|
+
raise Minty::InvalidParameter, 'Must supply a valid jwks_url' if jwks_url.to_s.empty?
|
64
|
+
|
65
|
+
unless lifetime.is_a?(Integer) && lifetime >= 0
|
66
|
+
raise Minty::InvalidParameter,
|
67
|
+
'Must supply a valid lifetime'
|
68
|
+
end
|
69
|
+
|
70
|
+
@lifetime = lifetime
|
71
|
+
@jwks_url = jwks_url
|
72
|
+
@did_fetch_jwks = false
|
73
|
+
end
|
74
|
+
|
75
|
+
def name
|
76
|
+
'RS256'
|
77
|
+
end
|
78
|
+
|
79
|
+
def jwks(force: false)
|
80
|
+
result = fetch_jwks if force
|
81
|
+
|
82
|
+
if result
|
83
|
+
@@cache.put(@jwks_url, result, lifetime: @lifetime)
|
84
|
+
return result
|
85
|
+
end
|
86
|
+
|
87
|
+
previous_value = @@cache.last(@jwks_url)
|
88
|
+
|
89
|
+
@@cache.get(@jwks_url, lifetime: @lifetime, dirty: true) do
|
90
|
+
new_value = fetch_jwks
|
91
|
+
|
92
|
+
raise Minty::InvalidIdToken, 'Could not fetch the JWK set' unless new_value || previous_value
|
93
|
+
|
94
|
+
new_value || previous_value
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def fetched_jwks?
|
99
|
+
@did_fetch_jwks
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def fetch_jwks
|
105
|
+
result = request_with_retry(:get, @jwks_url, {}, {})
|
106
|
+
@did_fetch_jwks = result.is_a?(Hash) && result.key?('keys')
|
107
|
+
result if @did_fetch_jwks
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/minty/mixins.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'rest-client'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
require 'minty/mixins/api_token_struct'
|
8
|
+
require 'minty/mixins/headers'
|
9
|
+
require 'minty/mixins/httpproxy'
|
10
|
+
require 'minty/mixins/initializer'
|
11
|
+
require 'minty/mixins/validation'
|
12
|
+
|
13
|
+
require 'minty/api/authentication_endpoints'
|
14
|
+
require 'minty/api/v2'
|
15
|
+
|
16
|
+
module Minty
|
17
|
+
# Collecting dependencies here
|
18
|
+
module Mixins
|
19
|
+
include Minty::Mixins::Headers
|
20
|
+
include Minty::Mixins::HTTPProxy
|
21
|
+
include Minty::Mixins::Initializer
|
22
|
+
end
|
23
|
+
end
|
data/lib/minty.rb
ADDED
data/lib/minty_client.rb
ADDED
data/minty.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'minty/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'minty'
|
7
|
+
s.version = Minty::VERSION
|
8
|
+
s.authors = ['Minty']
|
9
|
+
s.email = ['support@minty.page']
|
10
|
+
s.homepage = 'https://github.com/mintypage/ruby'
|
11
|
+
s.summary = 'Minty API Client'
|
12
|
+
s.description = 'Ruby toolkit for Minty API https://minty.page'
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.add_runtime_dependency 'rest-client', '~> 2.1'
|
20
|
+
s.add_runtime_dependency 'jwt', '~> 2.5'
|
21
|
+
s.add_runtime_dependency 'zache', '~> 0.12'
|
22
|
+
s.add_runtime_dependency 'addressable', '~> 2.8'
|
23
|
+
s.add_runtime_dependency 'retryable', '~> 3.0'
|
24
|
+
|
25
|
+
s.add_development_dependency 'bundler'
|
26
|
+
s.add_development_dependency 'rake', '~> 13.0'
|
27
|
+
s.add_development_dependency 'fuubar', '~> 2.0'
|
28
|
+
s.add_development_dependency 'guard-rspec', '~> 4.5' unless ENV['CIRCLECI']
|
29
|
+
s.add_development_dependency 'dotenv-rails', '~> 2.0'
|
30
|
+
s.add_development_dependency 'pry', '~> 0.10'
|
31
|
+
s.add_development_dependency 'pry-nav', '~> 0.2'
|
32
|
+
s.add_development_dependency 'rspec', '~> 3.11'
|
33
|
+
s.add_development_dependency 'rack-test', '~> 0.6'
|
34
|
+
s.add_development_dependency 'rack', '~> 2.1'
|
35
|
+
s.add_development_dependency 'simplecov', '~> 0.9'
|
36
|
+
s.add_development_dependency 'faker', '~> 2.0'
|
37
|
+
s.add_development_dependency 'gem-release', '~> 0.7'
|
38
|
+
s.license = 'MIT'
|
39
|
+
end
|
data/publish_rubygem.sh
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# Create directory for rubygems credentials
|
4
|
+
mkdir /root/.gem
|
5
|
+
# Get API key from rubygems.org
|
6
|
+
curl -u "$RUBYGEMS_EMAIL":"$RUBYGEMS_PASSWORD" https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
|
7
|
+
# Build Gem
|
8
|
+
gem build minty.gemspec
|
9
|
+
# Publish Gem
|
10
|
+
gem push minty-*.gem
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
describe Minty::Api::AuthenticationEndpoints do
|
5
|
+
attr_reader :client, :test_user_email, :test_user_pwd, :test_user
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@client = MintyClient.new(v2_creds)
|
9
|
+
|
10
|
+
@test_user_email = "#{entity_suffix}-username-1@minty.page"
|
11
|
+
@test_user_pwd = '23kejn2jk3en2jke2jk3be2jk3ber'
|
12
|
+
|
13
|
+
VCR.use_cassette('Minty_Api_AuthenticationEndpoints/create_test_user') do
|
14
|
+
@test_user ||= @client.signup(
|
15
|
+
test_user_email,
|
16
|
+
test_user_pwd
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
after(:all) do
|
22
|
+
VCR.use_cassette('Minty_Api_AuthenticationEndpoints/delete_test_user') do
|
23
|
+
@client.delete_user("minty|#{test_user['_id']}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '.signup', vcr: true do
|
28
|
+
it 'should signup a new user' do
|
29
|
+
expect(test_user).to(include('_id', 'email'))
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should return the correct email address' do
|
33
|
+
expect(test_user['email']).to eq test_user_email
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '.change_password', vcr: true do
|
38
|
+
it 'should trigger a password reset' do
|
39
|
+
expect(
|
40
|
+
@client.change_password(test_user_email, '')
|
41
|
+
).to(include("We've just sent you an email to reset your password."))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '.saml_metadata', vcr: true do
|
46
|
+
it 'should retrieve SAML metadata' do
|
47
|
+
expect(@client.saml_metadata).to(include('<EntityDescriptor'))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '.wsfed_metadata', vcr: true do
|
52
|
+
it 'should retrieve WSFED metadata' do
|
53
|
+
expect(@client.wsfed_metadata).to(include('<EntityDescriptor'))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '.userinfo', vcr: true do
|
58
|
+
it 'should fail as not authorized' do
|
59
|
+
expect do
|
60
|
+
@client.userinfo('invalid_token')
|
61
|
+
end.to raise_error Minty::Unauthorized
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should return the userinfo' do
|
65
|
+
tokens = @client.login_with_resource_owner(test_user_email, test_user_pwd)
|
66
|
+
expect(@client.userinfo(tokens['access_token'])).to(
|
67
|
+
include('email' => test_user_email)
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '.login_with_resource_owner', vcr: true do
|
73
|
+
it 'should fail with an incorrect email' do
|
74
|
+
expect do
|
75
|
+
@client.login_with_resource_owner(
|
76
|
+
"#{test_user['email']}_invalid",
|
77
|
+
test_user_pwd
|
78
|
+
)
|
79
|
+
end.to raise_error Minty::AccessDenied
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should fail with an incorrect password' do
|
83
|
+
expect do
|
84
|
+
@client.login_with_resource_owner(
|
85
|
+
test_user['email'],
|
86
|
+
"#{test_user_pwd}_invalid"
|
87
|
+
)
|
88
|
+
end.to raise_error Minty::AccessDenied
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should login successfully with a default scope' do
|
92
|
+
expect(
|
93
|
+
@client.login_with_resource_owner(
|
94
|
+
test_user['email'],
|
95
|
+
test_user_pwd
|
96
|
+
).token
|
97
|
+
).to_not be_empty
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should fail with an invalid audience' do
|
101
|
+
expect do
|
102
|
+
@client.login_with_resource_owner(
|
103
|
+
test_user['email'],
|
104
|
+
test_user_pwd,
|
105
|
+
scope: 'test:scope',
|
106
|
+
audience: 'https://brucke.club/invalid/api/v1/'
|
107
|
+
)
|
108
|
+
end.to raise_error Minty::BadRequest
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should login successfully with a custom audience' do
|
112
|
+
expect(
|
113
|
+
@client.login_with_resource_owner(
|
114
|
+
test_user['email'],
|
115
|
+
test_user_pwd,
|
116
|
+
scope: 'test:scope',
|
117
|
+
audience: 'https://brucke.club/custom/api/v1/'
|
118
|
+
).token
|
119
|
+
).to_not be_empty
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
describe Minty::Client do
|
5
|
+
shared_examples 'invalid credentials' do |credentials, error|
|
6
|
+
it "raise an error with credentials #{credentials}" do
|
7
|
+
if error.nil?
|
8
|
+
expect { MintyClient.new(credentials) }.to raise_error
|
9
|
+
else
|
10
|
+
expect { MintyClient.new(credentials) }.to raise_error(error)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it_should_behave_like 'invalid credentials', {
|
16
|
+
namespace: 'samples.minty.page'
|
17
|
+
}, Minty::InvalidCredentials
|
18
|
+
|
19
|
+
it_should_behave_like 'invalid credentials', {
|
20
|
+
namespace: 'samples.minty.page', client_id: 'client_id'
|
21
|
+
}, Minty::InvalidCredentials
|
22
|
+
|
23
|
+
it_should_behave_like 'invalid credentials', {
|
24
|
+
namespace: 'samples.minty.page', client_secret: 'secret'
|
25
|
+
}, Minty::InvalidCredentials
|
26
|
+
|
27
|
+
it_should_behave_like 'invalid credentials', {
|
28
|
+
namespace: 'samples.minty.page', api_version: 2
|
29
|
+
}, Minty::InvalidCredentials
|
30
|
+
|
31
|
+
it_should_behave_like 'invalid credentials', {}, Minty::InvalidApiNamespace
|
32
|
+
|
33
|
+
it_should_behave_like 'invalid credentials', {
|
34
|
+
api_version: 2
|
35
|
+
}, Minty::InvalidApiNamespace
|
36
|
+
|
37
|
+
it_should_behave_like 'invalid credentials', {
|
38
|
+
api_version: 1
|
39
|
+
}, Minty::InvalidApiNamespace
|
40
|
+
|
41
|
+
it_should_behave_like 'invalid credentials', {
|
42
|
+
client_id: 'client_id', client_secret: 'secret'
|
43
|
+
}, Minty::InvalidApiNamespace
|
44
|
+
|
45
|
+
it_should_behave_like 'invalid credentials', {
|
46
|
+
api_version: 2, token: 'token'
|
47
|
+
}, Minty::InvalidApiNamespace
|
48
|
+
|
49
|
+
let(:v2_credentials) { { domain: 'test.minty.page' } }
|
50
|
+
|
51
|
+
shared_examples 'valid credentials' do
|
52
|
+
it { expect { MintyClient.new(credentials) }.to_not raise_error }
|
53
|
+
end
|
54
|
+
|
55
|
+
it_should_behave_like 'valid credentials' do
|
56
|
+
let(:credentials) { v2_credentials.merge(token: 'TEST_API_TOKEN') }
|
57
|
+
end
|
58
|
+
|
59
|
+
it_should_behave_like 'valid credentials' do
|
60
|
+
let(:credentials) { v2_credentials.merge(access_token: 'TEST_API_TOKEN') }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'client headers' do
|
64
|
+
let(:client) { Minty::Client.new(v2_credentials.merge(access_token: 'abc123', domain: 'myhost.minty.page')) }
|
65
|
+
let(:headers) { client.headers }
|
66
|
+
let(:telemetry) { JSON.parse(Base64.urlsafe_decode64(headers['Minty-Client'])) }
|
67
|
+
|
68
|
+
it 'has the correct headers present' do
|
69
|
+
expect(headers.keys.sort).to eql(%w[Minty-Client Authorization Content-Type])
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'uses the correct access token' do
|
73
|
+
expect(headers['Authorization']).to eql 'Bearer abc123'
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'is always json' do
|
77
|
+
expect(headers['Content-Type']).to eql 'application/json'
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should include the correct name in telemetry data' do
|
81
|
+
expect(telemetry['name']).to eq('ruby')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should include the correct version in telemetry data' do
|
85
|
+
expect(telemetry['version']).to eq(Minty::VERSION)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should include the correct env in telemetry data' do
|
89
|
+
expect(telemetry['env']['ruby']).to eq(RUBY_VERSION)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|