authinator 0.0.1 → 0.0.2

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: d74ae2cc632fa497d66db160895f23b467ecf229
4
- data.tar.gz: b94bb79f1f6a8a2bf4590f3bda38c67cee7cdf1c
3
+ metadata.gz: b3b66719b8c7bb8dd6f60aa7e7ed026b661672f3
4
+ data.tar.gz: f9d3351fe755049be4cf3ed7b2c1cf3ab8dd6876
5
5
  SHA512:
6
- metadata.gz: cb6b27be793d25bee657b48791648ffe740a0efa52f0e07d7a704ffb4b51e0b6c4c775f36888c1cd130acb364eb14f2ebcc5ceb673e8d34f8fb85eedd4d452bb
7
- data.tar.gz: a536e204bae88a4a8daf8492d83fd1fa22b1013d8812e0716e29e4a4a47603d019bbe5db6c0d6127cd9e44c0255fccaa7c958f74f6c4d4f3bcbd5f52a9aedc98
6
+ metadata.gz: 8d3cdbe4ffd69f2fcfab7931eefc43ebbadc7214f02207bf42ad822d5330a62dbe2f6a46fc3a1c16239da4c6a33e180d7f021378252112c87b1bb40a2508cef3
7
+ data.tar.gz: cc7c802bae55aaf6e44a4c3ef220bdbfa4ab8ae6014a2236e841d27c4235dd53e98938f49f729560121988bd4edbf19cf0f1cb7450006d841297bde4b899e99c
data/.gitignore CHANGED
@@ -11,4 +11,5 @@
11
11
  *.so
12
12
  *.o
13
13
  *.a
14
+ *.gem
14
15
  mkmf.log
data/.rubocop.yml CHANGED
@@ -47,3 +47,7 @@ Style/Lambda:
47
47
 
48
48
  Style/TrailingComma:
49
49
  EnforcedStyleForMultiline: 'comma'
50
+
51
+ # Avoid complex methods.
52
+ Metrics/CyclomaticComplexity:
53
+ Max: 7
data/.travis.yml CHANGED
@@ -4,12 +4,12 @@ env:
4
4
  - JRUBY_OPTS="$JRUBY_OPTS --debug"
5
5
  language: ruby
6
6
  rvm:
7
+ - rbx-2
8
+ - jruby-19mode
7
9
  - 1.9.3
8
10
  - 2.0.0
9
11
  - 2.1
10
- - jruby-19mode
11
12
  - jruby-head
12
- - rbx-2
13
13
  - ruby-head
14
14
  matrix:
15
15
  allow_failures:
data/lib/authinator.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'authinator/version'
2
2
  require 'authinator/auth_code_exchanger'
3
+ require 'authinator/end_point_listener'
4
+ require 'authinator/client_token_issuer'
3
5
 
4
6
  module Authinator
5
7
  # Your code goes here...
@@ -2,99 +2,99 @@
2
2
  # require 'omniauth-oauth2'
3
3
  require 'oauth2'
4
4
 
5
- # module Authinator
6
- class AuthCodeExchanger
7
- VALID_PROVIDERS = [:stub, :google]
8
- STUB_SAMPLE_TOKEN = {
9
- token: 'ya29.token',
10
- refresh_token: '1/refresh',
11
- expires_in: 3600,
12
- }
13
-
14
- attr_reader :provider
15
-
16
- def self.valid_providers
17
- VALID_PROVIDERS
18
- end
19
-
20
- PROVIDER_HASHES = {
21
- google: {
22
- client_id: 'cl_id',
23
- client_secret: 'cl_sec',
24
- site: 'https://accounts.google.com',
25
- token_url: '/o/oauth2/token',
26
- },
27
- stub: {
28
- client_id: 'cl_id',
29
- client_secret: 'cl_sec',
30
- site: 'https://example.org',
31
- token_url: '/extoken',
32
- },
33
- }
34
-
35
- def initialize(provider, client_options = {})
36
- unless VALID_PROVIDERS.include? provider
37
- fail ArgumentError,
38
- "Provider #{provider} not in supported parameter list:\n" <<
39
- VALID_PROVIDERS.inspect
5
+ module Authinator
6
+ class AuthCodeExchanger
7
+ VALID_PROVIDERS = [:stub, :google]
8
+ STUB_SAMPLE_TOKEN = {
9
+ token: 'ya29.token',
10
+ refresh_token: '1/refresh',
11
+ expires_in: 3600,
12
+ }
13
+
14
+ attr_reader :provider
15
+
16
+ def self.valid_providers
17
+ VALID_PROVIDERS
40
18
  end
41
19
 
42
- @provider = provider
43
- build_provider_hash(client_options)
44
- end
20
+ PROVIDER_HASHES = {
21
+ google: {
22
+ client_id: 'cl_id',
23
+ client_secret: 'cl_sec',
24
+ site: 'https://accounts.google.com',
25
+ token_url: '/o/oauth2/token',
26
+ },
27
+ stub: {
28
+ client_id: 'cl_id',
29
+ client_secret: 'cl_sec',
30
+ site: 'https://example.org',
31
+ token_url: '/extoken',
32
+ },
33
+ }
34
+
35
+ def initialize(provider, client_options = {})
36
+ unless VALID_PROVIDERS.include? provider
37
+ fail ArgumentError,
38
+ "Provider #{provider} not in supported parameter list:\n" <<
39
+ VALID_PROVIDERS.inspect
40
+ end
41
+
42
+ @provider = provider
43
+ build_provider_hash(client_options)
44
+ end
45
45
 
46
- def site_token_url
47
- @provider_hash[:site] + @provider_hash[:token_url]
48
- end
46
+ def site_token_url
47
+ @provider_hash[:site] + @provider_hash[:token_url]
48
+ end
49
49
 
50
- def exchange(auth_code)
51
- # auth_code = params[:code]
52
- return if auth_code.nil? || auth_code.empty?
50
+ def exchange(auth_code)
51
+ # auth_code = params[:code]
52
+ return if auth_code.nil? || auth_code.empty?
53
53
 
54
- case @provider.to_sym
55
- when :google
56
- exchange_with_google(auth_code)
57
- when :stub
58
- exchange_with_stub(auth_code)
54
+ case @provider.to_sym
55
+ when :google
56
+ exchange_with_google(auth_code)
57
+ when :stub
58
+ exchange_with_stub(auth_code)
59
+ end
59
60
  end
60
- end
61
61
 
62
- private
62
+ private
63
63
 
64
- def build_provider_hash(client_options)
65
- @provider_hash = PROVIDER_HASHES[provider]
66
- @provider_hash = client_options.delete(:client_id) if client_options[:client_id]
67
- @provider_hash = client_options.delete(:client_secret) if client_options[:client_secret]
68
- end
64
+ def build_provider_hash(client_options)
65
+ @provider_hash = PROVIDER_HASHES[provider]
66
+ @provider_hash = client_options.delete(:client_id) if client_options[:client_id]
67
+ @provider_hash = client_options.delete(:client_secret) if client_options[:client_secret]
68
+ end
69
69
 
70
- def exchange_with_google(code)
71
- provider_hash = @provider_hash.dup
70
+ def exchange_with_google(code)
71
+ provider_hash = @provider_hash.dup
72
72
 
73
- client_id = provider_hash.delete(:client_id)
74
- client_secret = provider_hash.delete(:client_secret)
75
- @client = OAuth2::Client.new(client_id, client_secret, provider_hash)
73
+ client_id = provider_hash.delete(:client_id)
74
+ client_secret = provider_hash.delete(:client_secret)
75
+ @client = OAuth2::Client.new(client_id, client_secret, provider_hash)
76
76
 
77
- token = @client.auth_code.get_token(code)
77
+ token = @client.auth_code.get_token(code)
78
78
 
79
- # response = token.get('/api/resource', :params => { 'query_foo' => 'bar' })
80
- # response.class.name
81
- # => OAuth2::Response
79
+ # response = token.get('/api/resource', :params => { 'query_foo' => 'bar' })
80
+ # response.class.name
81
+ # => OAuth2::Response
82
82
 
83
- token
84
- end
83
+ token
84
+ end
85
85
 
86
- def exchange_with_stub(_code)
87
- @client = OAuth2::Client.new(
88
- @provider_hash[:client_id],
89
- @provider_hash[:client_secret],
90
- )
91
-
92
- OAuth2::AccessToken.new(
93
- @client,
94
- STUB_SAMPLE_TOKEN[:token],
95
- refresh_token: STUB_SAMPLE_TOKEN[:refresh_token],
96
- expires_in: STUB_SAMPLE_TOKEN[:expires_in],
97
- )
86
+ def exchange_with_stub(_code)
87
+ @client = OAuth2::Client.new(
88
+ @provider_hash[:client_id],
89
+ @provider_hash[:client_secret],
90
+ )
91
+
92
+ OAuth2::AccessToken.new(
93
+ @client,
94
+ STUB_SAMPLE_TOKEN[:token],
95
+ refresh_token: STUB_SAMPLE_TOKEN[:refresh_token],
96
+ expires_in: STUB_SAMPLE_TOKEN[:expires_in],
97
+ )
98
+ end
98
99
  end
99
100
  end
100
- # end
@@ -0,0 +1,4 @@
1
+ module Authinator
2
+ class ClientTokenIssuer
3
+ end
4
+ end
@@ -0,0 +1,58 @@
1
+ module Authinator
2
+ class EndPointListener
3
+ attr_reader :email, :provider, :auth_code, :options, :errors
4
+
5
+ def initialize(hash = {})
6
+ @email = hash.delete :email
7
+ @provider = hash.delete :provider
8
+ @auth_code = hash.delete :auth_code
9
+ @options = hash
10
+ @errors = []
11
+ end
12
+
13
+ def valid?
14
+ validator_presence? &&
15
+ validator_valid_email? &&
16
+ validator_valid_provider?
17
+ end
18
+
19
+ private
20
+
21
+ def validator_presence?
22
+ email_present = present? @email
23
+ provider_present = present? @provider
24
+ auth_code_present = present? @auth_code
25
+
26
+ return true if email_present && provider_present && auth_code_present
27
+ errors << 'A required param is missing'
28
+ errors << '"email" field missing' unless email_present
29
+ errors << '"provider" field missing' unless provider_present
30
+ errors << '"auth_code" field missing' unless auth_code_present
31
+ false
32
+ end
33
+
34
+ # Regexp lovingly borrowed from https://github.com/balexand/email_validator
35
+ def validator_valid_email?
36
+ name_validation = @options[:strict_mode] ? '-a-z0-9+._' : '^@\\s'
37
+ regexp = /\A\s*([#{name_validation}]{1,64})@((?:[-a-z0-9]+\.)+[a-z]{2,})\s*\z/i
38
+ return true if @email =~ regexp
39
+ errors << "Email '#{@email}' is invalid"
40
+ false
41
+ end
42
+
43
+ def validator_valid_provider?
44
+ return true if Authinator::AuthCodeExchanger.valid_providers.include? @provider.to_sym
45
+ errors << "Provider '#{@provider}' is invalid"
46
+ false
47
+ end
48
+
49
+ # recreate rails method
50
+ def present?(el)
51
+ !blank?(el)
52
+ end
53
+
54
+ def blank?(el)
55
+ el.nil? || el.empty?
56
+ end
57
+ end
58
+ end
@@ -1,3 +1,3 @@
1
1
  module Authinator
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'json'
3
3
 
4
- describe AuthCodeExchanger do
4
+ describe Authinator::AuthCodeExchanger do
5
5
  before :all do
6
6
  @token_hash = {
7
7
  access_token: 'ya29.token',
@@ -29,7 +29,7 @@ describe AuthCodeExchanger do
29
29
  }
30
30
  end
31
31
  it 'should correctly process a generic (stub) token' do
32
- ace = AuthCodeExchanger.new(:stub)
32
+ ace = Authinator::AuthCodeExchanger.new(:stub)
33
33
  stub_request(:post, ace.site_token_url).
34
34
  with(body: @test_env,
35
35
  headers: @req_headers).
@@ -45,8 +45,8 @@ describe AuthCodeExchanger do
45
45
  it 'should return an AccessToken for each provider' do
46
46
  klass = OAuth2::AccessToken
47
47
 
48
- AuthCodeExchanger.valid_providers.each do |provider|
49
- ace = AuthCodeExchanger.new(provider)
48
+ Authinator::AuthCodeExchanger.valid_providers.each do |provider|
49
+ ace = Authinator::AuthCodeExchanger.new(provider)
50
50
  stub_request(:post, ace.site_token_url).
51
51
  with(body: @test_env,
52
52
  headers: @req_headers).
@@ -57,7 +57,7 @@ describe AuthCodeExchanger do
57
57
  end
58
58
 
59
59
  it 'should correctly process a google token' do
60
- ace = AuthCodeExchanger.new(:google)
60
+ ace = Authinator::AuthCodeExchanger.new(:google)
61
61
  stub_request(:post, ace.site_token_url).
62
62
  with(body: @test_env,
63
63
  headers: @req_headers).
@@ -72,18 +72,7 @@ describe AuthCodeExchanger do
72
72
 
73
73
  it 'should gracefully not allow unsupported providers' do
74
74
  expect do
75
- AuthCodeExchanger.new(:some_fake_provider)
75
+ Authinator::AuthCodeExchanger.new(:some_fake_provider)
76
76
  end.to raise_error(ArgumentError)
77
77
  end
78
78
  end
79
-
80
- describe 'ClientTokenIssuer' do
81
- pending
82
- it 'should accept valid-looking credentials from the client'
83
- it 'should exchange client-provided credentials for auth codes'
84
- it 'should return an error to the client if the credentials were invalid'
85
- it 'should verify that the tokens belong to the provided email before returning them'
86
- it 'should generate our own set of tokens for the client if the provided ones exchanged successfully'
87
-
88
- it 'should all integrate to follow a standard flow to auth the api client'
89
- end
@@ -0,0 +1,8 @@
1
+ describe Authinator::ClientTokenIssuer do
2
+ it 'should exchange client-provided credentials for auth codes'
3
+ it 'should gracefully handle and return error condition if client-provided credentials are invalid'
4
+ it 'should verify that the tokens belong to the provided email before returning them'
5
+ it 'should generate our own set of tokens for the client if the provided ones exchanged successfully'
6
+
7
+ it 'should all integrate to follow a standard flow to auth the api client'
8
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe Authinator::EndPointListener do
4
+ before :each do
5
+ @creds_hash = {
6
+ email: 'test@foogi.me',
7
+ auth_code: '4/auth_code',
8
+ provider: 'google',
9
+ }
10
+ end
11
+ it 'should accept valid-looking credentials from the client' do
12
+ listener = Authinator::EndPointListener.new(@creds_hash)
13
+ expect(listener.valid?).to be_truthy
14
+ end
15
+
16
+ # These tests extend on the test above.
17
+ # Given the test above handles the happy path, everything below are sad path tests
18
+
19
+ it 'should return an error to the client if the credentials were invalid' do
20
+ bad_creds_hash = {
21
+ a: 'b',
22
+ c: 'd',
23
+ }
24
+ listener = Authinator::EndPointListener.new(bad_creds_hash)
25
+ expect(listener.valid?).to be_falsey
26
+ end
27
+ it 'should return an error unless all three fields are provided' do
28
+ listener1 = Authinator::EndPointListener.new(@creds_hash.dup.tap { |hs| hs.delete(:email) }) # remove email
29
+ listener2 = Authinator::EndPointListener.new(@creds_hash.dup.tap { |hs| hs.delete(:auth_code) }) # remove ac
30
+ listener3 = Authinator::EndPointListener.new(@creds_hash.dup.tap { |hs| hs.delete(:provider) }) # remove prov
31
+
32
+ expect(listener1.valid?).to be_falsey
33
+ expect(listener2.valid?).to be_falsey
34
+ expect(listener3.valid?).to be_falsey
35
+ end
36
+ it 'should reject invalid emails' do
37
+ bad_email_hash1 = @creds_hash.merge(email: 'abc')
38
+ bad_email_hash2 = @creds_hash.merge(email: '')
39
+ bad_email_hash3 = @creds_hash.merge(email: 'a@')
40
+
41
+ listener1 = Authinator::EndPointListener.new(bad_email_hash1)
42
+ listener2 = Authinator::EndPointListener.new(bad_email_hash2)
43
+ listener3 = Authinator::EndPointListener.new(bad_email_hash3)
44
+
45
+ expect(listener1.valid?).to be_falsey
46
+ expect(listener2.valid?).to be_falsey
47
+ expect(listener3.valid?).to be_falsey
48
+ end
49
+
50
+ it 'should reject invalid providers' do
51
+ bad_provider_hash1 = @creds_hash.merge(provider: 'some_fake_provider')
52
+ bad_provider_hash2 = @creds_hash.merge(provider: '')
53
+
54
+ listener1 = Authinator::EndPointListener.new(bad_provider_hash1)
55
+ listener2 = Authinator::EndPointListener.new(bad_provider_hash2)
56
+
57
+ expect(listener1.valid?).to be_falsey
58
+ expect(listener2.valid?).to be_falsey
59
+ end
60
+
61
+ it 'should return a human-readable list of errors if there are any' do
62
+ listener = Authinator::EndPointListener.new({})
63
+ listener.valid?
64
+ expect(listener.errors).to eq [
65
+ 'A required param is missing',
66
+ '"email" field missing',
67
+ '"provider" field missing',
68
+ '"auth_code" field missing',
69
+ ]
70
+ end
71
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authinator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Bradner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-21 00:00:00.000000000 Z
11
+ date: 2014-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oauth2
@@ -114,8 +114,12 @@ files:
114
114
  - authinator.gemspec
115
115
  - lib/authinator.rb
116
116
  - lib/authinator/auth_code_exchanger.rb
117
+ - lib/authinator/client_token_issuer.rb
118
+ - lib/authinator/end_point_listener.rb
117
119
  - lib/authinator/version.rb
118
- - spec/authinator/authinator_spec.rb
120
+ - spec/authinator/auth_code_exchanger_spec.rb
121
+ - spec/authinator/client_token_issuer_spec.rb
122
+ - spec/authinator/end_point_listener_spec.rb
119
123
  - spec/spec_helper.rb
120
124
  homepage: https://github.com/abradner/authinator
121
125
  licenses:
@@ -142,5 +146,7 @@ signing_key:
142
146
  specification_version: 4
143
147
  summary: Single-Sign-On for the front and rails backend of a Single-Page-App
144
148
  test_files:
145
- - spec/authinator/authinator_spec.rb
149
+ - spec/authinator/auth_code_exchanger_spec.rb
150
+ - spec/authinator/client_token_issuer_spec.rb
151
+ - spec/authinator/end_point_listener_spec.rb
146
152
  - spec/spec_helper.rb