holistic_auth 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d134bcc56c80376e039b96488f493657ba8acc35
4
+ data.tar.gz: 36fb20712f7771ed77e259c4e049380caca4d628
5
+ SHA512:
6
+ metadata.gz: 1b6c280cb443d173da63b58c784cb856151413aade51dcb34abdcde225c3150413ba543e368e52b3b55dbdce84d1de04ba1356655e713025da858ace073da13f
7
+ data.tar.gz: 6521ee9607847f88b1332c38234ac3157b5f0685d7d6b051836d9ee9f5823eb7939f88ec750ac5543a24dd175d13865b986b40ff76c3b0d9fd59633ea5fae359
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ *.gem
15
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.rubocop.yml ADDED
@@ -0,0 +1,62 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'holistic_auth.gemspec'
4
+
5
+ Metrics/BlockNesting:
6
+ Max: 2
7
+
8
+ Metrics/LineLength:
9
+ AllowURI: true
10
+ Enabled: false
11
+
12
+ Metrics/MethodLength:
13
+ CountComments: false
14
+ Max: 20
15
+
16
+ Metrics/ParameterLists:
17
+ Max: 4
18
+ CountKeywordArgs: true
19
+
20
+ Style/AccessModifierIndentation:
21
+ EnforcedStyle: outdent
22
+
23
+ Style/CollectionMethods:
24
+ PreferredMethods:
25
+ map: 'collect'
26
+ reduce: 'inject'
27
+ find: 'detect'
28
+ find_all: 'select'
29
+
30
+ Style/Documentation:
31
+ Enabled: false
32
+
33
+ Style/DotPosition:
34
+ EnforcedStyle: trailing
35
+
36
+ Style/DoubleNegation:
37
+ Enabled: false
38
+
39
+ Style/EachWithObject:
40
+ Enabled: false
41
+
42
+ Style/Encoding:
43
+ Enabled: false
44
+
45
+ Style/Lambda:
46
+ Enabled: false
47
+
48
+ Style/TrailingCommaInLiteral:
49
+ EnforcedStyleForMultiline: 'comma'
50
+
51
+ Style/TrailingCommaInArguments:
52
+ EnforcedStyleForMultiline: 'comma'
53
+
54
+ # Avoid complex methods.
55
+ Metrics/CyclomaticComplexity:
56
+ Max: 7
57
+
58
+ Metrics/AbcSize:
59
+ Max: 20
60
+
61
+ Style/CaseIndentation:
62
+ IndentOneStep: true
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ holistic_auth
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.4
data/.travis.yml ADDED
@@ -0,0 +1,22 @@
1
+ before_install:
2
+ - gem update bundler
3
+ bundler_args: "--without development"
4
+ env:
5
+ global:
6
+ - JRUBY_OPTS="$JRUBY_OPTS --debug"
7
+ language: ruby
8
+ rvm:
9
+ - 2.2
10
+ - 2.1
11
+ - 2.0.0
12
+ - 2.3
13
+ - ruby-head
14
+ matrix:
15
+ allow_failures:
16
+ - rvm: 2.3
17
+ - rvm: ruby-head
18
+ fast_finish: true
19
+ sudo: false
20
+ notifications:
21
+ slack:
22
+ secure: G6D51WJ/dtKpab6CUWMMEha3Joo5SwM4ycfYMAJFhmV4Zzs0wcPAWOU2jsFydYIUXkM8pkUnEn6scW3k01eTXZ7P/QYMMJqwZ6OvTH80x7mZj+WfD0vbQAg1lHYus32ADXI0F3IqTOlG/M4D9USe2TJmFI3sZ7+U0jPINOBLSWA=
data/Gemfile ADDED
@@ -0,0 +1,21 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in holistic_auth.gemspec
4
+ gemspec
5
+
6
+ gem 'rake'
7
+
8
+ group :test do
9
+ gem 'coveralls'
10
+ gem 'json', platforms: [:jruby, :ruby_18, :ruby_19]
11
+ gem 'mime-types', '~> 2.4.0', platforms: [:jruby, :ruby_18]
12
+ gem 'rack-test'
13
+ gem 'rest-client', '~> 1.7.0', platforms: [:jruby, :ruby_18]
14
+ gem 'rspec', '~> 3.2.0'
15
+ gem 'rubocop', '>= 0.28', platforms: [:ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23]
16
+ gem 'simplecov', '>= 0.9'
17
+ gem 'webmock'
18
+ end
19
+
20
+ # gem 'abstract_google_client', path: '/Users/abradner/foogi/google_client', require: 'google_client'
21
+ gem 'abstract_google_client', github: 'abradner/google_client', require: 'google_client'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Alexander Bradner
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # Ruby Holistic Auth
2
+ [![Gem Version](http://img.shields.io/gem/v/holistic_auth.svg)][gem]
3
+ [![Build Status](http://img.shields.io/travis/abradner/holistic_auth.svg)][travis]
4
+ [![Dependency Status](http://img.shields.io/gemnasium/abradner/holistic_auth.svg)][gemnasium]
5
+ [![Code Climate](http://img.shields.io/codeclimate/github/abradner/holistic_auth.svg)][codeclimate]
6
+ [![Coverage Status](http://img.shields.io/coveralls/abradner/holistic_auth.svg)][coveralls]
7
+
8
+ [gem]: https://rubygems.org/gems/holistic_auth
9
+ [travis]: http://travis-ci.org/abradner/holistic_auth
10
+ [gemnasium]: https://gemnasium.com/abradner/holistic_auth
11
+ [codeclimate]: https://codeclimate.com/github/abradner/holistic_auth
12
+ [coveralls]: https://coveralls.io/r/abradner/holistic_auth
13
+
14
+ TODO: Write a gem description
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'holistic_auth'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Or install it yourself as:
29
+
30
+ $ gem install holistic_auth
31
+
32
+ ## Usage
33
+
34
+ TODO: Write usage instructions here
35
+
36
+ ## Contributing
37
+
38
+ 1. Fork it ( https://github.com/abradner/holistic_auth/fork )
39
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
40
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
41
+ 4. Push to the branch (`git push origin my-new-feature`)
42
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new
6
+
7
+ task test: :spec
8
+
9
+ begin
10
+ require 'rubocop/rake_task'
11
+ RuboCop::RakeTask.new
12
+ rescue LoadError
13
+ task :rubocop do
14
+ $stderr.puts 'RuboCop is disabled'
15
+ end
16
+ end
17
+
18
+ task default: [:spec, :rubocop]
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'holistic_auth/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'holistic_auth'
8
+ spec.version = HolisticAuth::VERSION
9
+ spec.authors = ['Alexander Bradner']
10
+ spec.email = ['alex@bradner.net']
11
+ spec.summary = 'Single-Sign-On for the front and rails backend of a Single-Page-App'
12
+ # spec.description = ''
13
+ spec.homepage = 'https://github.com/abradner/holistic_auth'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_runtime_dependency 'oauth2', '~> 1.0'
22
+ spec.add_runtime_dependency 'doorkeeper', '~> 2.0'
23
+ spec.add_runtime_dependency 'activesupport', '>= 4.2'
24
+ spec.add_runtime_dependency 'activerecord', '>= 4.2'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.7'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec', '~> 3'
29
+ spec.add_development_dependency 'rubocop'
30
+ end
@@ -0,0 +1,17 @@
1
+ require 'active_support/all'
2
+ require 'holistic_auth/version'
3
+ require 'holistic_auth/errors'
4
+ require 'holistic_auth/configuration'
5
+ require 'holistic_auth/end_point_listener'
6
+ require 'holistic_auth/client_token_issuer'
7
+
8
+ require 'holistic_auth/providers/generic_provider'
9
+ require 'holistic_auth/providers/stub'
10
+ require 'holistic_auth/providers/google'
11
+ require 'holistic_auth/providers/ms_graph'
12
+ require 'holistic_auth/providers/outlook'
13
+
14
+ require 'holistic_auth/orm_handlers/active_record'
15
+
16
+ module HolisticAuth
17
+ end
@@ -0,0 +1,106 @@
1
+ module HolisticAuth
2
+ class ClientTokenIssuer
3
+ # Options can
4
+ def initialize(params, options = {})
5
+ @params = params.with_indifferent_access
6
+ provider_name = get_provider_name(options)
7
+ unless HolisticAuth.configuration.providers.include? provider_name
8
+ raise ArgumentError,
9
+ "Provider #{provider_name} not in supported provider list:\n" <<
10
+ HolisticAuth.configuration.providers.inspect
11
+ end
12
+
13
+ @provider = HolisticAuth.configuration.provider(provider_name)
14
+
15
+ assign_instance_vars(options)
16
+ end
17
+
18
+ def authorize!(options = {})
19
+ return { error: "Invalid Application #{@app_name}" }, :bad_request unless @valid_applications.include? @app_name
20
+
21
+ validator = EndPointListener.new(auth_code: @auth_code, provider: @provider)
22
+ raise "End provider/config not valid:\n #{validator.inspect}" unless validator.valid?
23
+
24
+ handle(options)
25
+ end
26
+
27
+ def handle(options = {})
28
+ provider_access_token = @provider.exchange @auth_code, @redirect_uri
29
+
30
+ begin
31
+ info = load_info(provider_access_token)
32
+ rescue EmailNotVerifiedError => _e
33
+ return { error: 'Cannot create a Foogi account with an unverified email address' }, :bad_request
34
+ end
35
+
36
+ orm_handler = HolisticAuth::OrmHandlers::ActiveRecord.new(info, @provider.name.to_s)
37
+
38
+ user = orm_handler.discover_user!
39
+ orm_handler.store_provider_credentials!(provider_access_token)
40
+
41
+ token_data = prepare_token(provider_access_token, user, options.delete(:expires_in))
42
+
43
+ [token_data.to_json, :ok]
44
+ end
45
+
46
+ def load_info(access_token)
47
+ # raw_info = provider_access_token.get('https://www.googleapis.com/plus/v1/people/me/openIdConnect').parsed
48
+
49
+ raw_info = @provider.retrieve_user_info(access_token)
50
+
51
+ verified_email = raw_info[:email_verified] ? raw_info[:email] : nil
52
+ raise EmailNotVerifiedError, 'Email not verified' unless verified_email.present?
53
+
54
+ raw_info
55
+ end
56
+
57
+ private
58
+
59
+ def prepare_token(provider_access_token, user, expires_in = 2.hours)
60
+ application = Doorkeeper::Application.where(name: @app_name)
61
+
62
+ client_access_token = Doorkeeper::AccessToken.create!(
63
+ application_id: application,
64
+ resource_owner_id: user.id,
65
+ expires_in: expires_in,
66
+ use_refresh_token: true,
67
+ scopes: :user,
68
+ )
69
+
70
+ {
71
+ access_token: client_access_token.token,
72
+ refresh_token: client_access_token.refresh_token,
73
+ token_type: 'bearer',
74
+ expires_in: client_access_token.expires_in,
75
+ user_id: user.to_param,
76
+ provider_access_token: provider_access_token.token,
77
+ provider_expires_in: provider_access_token.expires_in,
78
+ # provider_id_token: provider_access_token.id_token,
79
+ }
80
+ end
81
+
82
+ def application_name
83
+ @params['application_name'].present? ? @params['application_name'].to_sym : nil
84
+ end
85
+
86
+ def prune!(hash)
87
+ hash.delete_if do |_, v|
88
+ prune!(v) if v.is_a?(Hash)
89
+ v.nil? || (v.respond_to?(:empty?) && v.empty?)
90
+ end
91
+ end
92
+
93
+ def get_provider_name(options)
94
+ return options.delete(:provider) if options[:provider]
95
+ return @params[:provider].to_sym if @params[:provider].present?
96
+ nil
97
+ end
98
+
99
+ def assign_instance_vars(options)
100
+ @auth_code = options.delete(:auth_code) || @params['code']
101
+ @redirect_uri = options.delete(:redirect_uri) || @params['redirect_uri']
102
+ @app_name = options.delete(:app_name) || application_name
103
+ @valid_applications = options.delete(:valid_applications) || HolisticAuth.configuration.valid_applications
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,67 @@
1
+ module HolisticAuth
2
+ # Exception to handle a missing initializer
3
+ # class MissingConfiguration < StandardError
4
+ # def initialize
5
+ # super('Configuration for holistic_auth missing. Do you have an HolisticAuth initializer?')
6
+ # end
7
+ # end
8
+
9
+ # Module level methods
10
+ class << self
11
+ attr_accessor :configuration
12
+ end
13
+
14
+ def self.configure
15
+ self.configuration ||= Configuration.new
16
+ yield(configuration)
17
+ end
18
+
19
+ # def self.configuration
20
+ # @config || (fail MissingConfiguration.new)
21
+ # end
22
+
23
+ # Configuration class
24
+ class Configuration
25
+ attr_reader :providers
26
+ attr_accessor :valid_applications
27
+
28
+ def initialize
29
+ @providers = {
30
+ stub: provider_for(:stub).new,
31
+ google: provider_for(:google).new,
32
+ ms_graph: provider_for(:ms_graph).new,
33
+ outlook: provider_for(:outlook).new,
34
+ }
35
+ end
36
+
37
+ def providers
38
+ @providers.keys
39
+ end
40
+
41
+ def provider(provider_name)
42
+ test_for_provider!(provider_name)
43
+ @providers[provider_name]
44
+ end
45
+
46
+ def add_secrets(provider_name, options = {})
47
+ test_for_provider!(provider_name)
48
+ @providers[provider_name].add_secrets(options)
49
+ end
50
+
51
+ private
52
+
53
+ def test_for_provider!(provider_name)
54
+ raise(
55
+ ArgumentError,
56
+ "#{provider_name} is not a configured provider.\n" \
57
+ "Valid Providers:\n" <<
58
+ providers.to_s,
59
+ ) if @providers[provider_name].nil?
60
+ end
61
+
62
+ # A more abstracted way of accessing the providers
63
+ def provider_for(provider_name)
64
+ "HolisticAuth::Providers::#{provider_name.to_s.camelize}".constantize
65
+ end
66
+ end
67
+ end