cloudcover 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2a63adaeeea97662bb92f5ff7a09b57982d3f101
4
+ data.tar.gz: 112b8afe37e3998c86ed74c9c08280a75ed15980
5
+ SHA512:
6
+ metadata.gz: 26f23e4d7d7ebed15e4a51c56d95f621833db58e4dfb4702db1ca4b9c575b000271f60918fdf5b758ca0193d3bad6c3f4067c80323218a2962935b4e71542e40
7
+ data.tar.gz: a4c5482e7ebd9992ac1693f3e7d4c0635f50678ba88bcc29fe9158f51fe7b8a4aca64340602daaadedb0bf05fdbf0125a48509d86d3988ef11b2352d9ffcf2e9
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ test.creds
2
+ .DS_Store
3
+ .idea
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.4
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cloudcover (0.0.1)
5
+ gli (~> 2.13.4)
6
+ hashdiff
7
+ highline
8
+ http-cookie
9
+ httparty
10
+ minitar
11
+ terminal-table
12
+
13
+ GEM
14
+ remote: https://rubygems.org/
15
+ specs:
16
+ domain_name (0.5.25)
17
+ unf (>= 0.0.5, < 1.0.0)
18
+ gli (2.13.4)
19
+ hashdiff (0.2.3)
20
+ highline (1.7.8)
21
+ http-cookie (1.0.2)
22
+ domain_name (~> 0.5)
23
+ httparty (0.13.7)
24
+ json (~> 1.8)
25
+ multi_xml (>= 0.5.2)
26
+ json (1.8.3)
27
+ minitar (0.5.4)
28
+ multi_xml (0.5.5)
29
+ rake (10.4.2)
30
+ rdoc (4.2.0)
31
+ json (~> 1.4)
32
+ terminal-table (1.5.2)
33
+ unf (0.1.4)
34
+ unf_ext
35
+ unf_ext (0.0.7.1)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ cloudcover!
42
+ rake
43
+ rdoc
44
+
45
+ BUNDLED WITH
46
+ 1.12.3
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ Cloudcover
2
+ --
3
+
4
+ A simple interface for using Okta authentication in command line applications
5
+
6
+ ```
7
+ NAME
8
+ cloudcover - A simple interface for using Okta authentication in command line applications
9
+
10
+ SYNOPSIS
11
+ cloudcover [global options] command [command options] [arguments...]
12
+
13
+ VERSION
14
+ 0.0.1
15
+
16
+ GLOBAL OPTIONS
17
+ --[no-]color - Colorize output (default: enabled)
18
+ --config=arg - Cloudcover config file path (default: /Users/mattkrieger/.cloudcover)
19
+ --cookie=arg - Cloudcover cookie file path (default: /Users/mattkrieger/.cloudcookie)
20
+ -d, --debug - Debug output (Includes verbose)
21
+ --help - Show this message
22
+ -v, --verbose - Verbose output
23
+ --version - Display the program version
24
+
25
+ COMMANDS
26
+ help - Shows a list of commands or help for one command
27
+ simple-auth - Simply verify that a set of credentials are valid to login to Okta
28
+ ```
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
5
+ Rake::RDocTask.new do |rd|
6
+ rd.main = "README.rdoc"
7
+ rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
8
+ rd.title = 'Cloudcover'
9
+ end
10
+
11
+ spec = eval(File.read('cloudcover.gemspec'))
12
+
13
+ Gem::PackageTask.new(spec) do |pkg|
14
+ end
data/bin/cloudcover ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+ require 'cloudcover'
4
+
5
+ include GLI::App
6
+
7
+ program_desc 'A simple interface for using Okta authentication in command line applications'
8
+
9
+ version Cloudcover::VERSION
10
+
11
+ subcommand_option_handling :normal
12
+ arguments :strict
13
+
14
+ switch [:v,:verbose], :desc => 'Verbose output', :negatable => false
15
+ switch [:d,:debug], :desc => 'Debug output (Includes verbose)', :negatable => false
16
+ switch [:color], :desc => 'Colorize output', :default_value => true
17
+ flag [:config], :desc => 'Cloudcover config file path', :default_value => File.join(ENV['HOME'],'.cloudcover')
18
+ flag ['session-path'], :desc => 'Cloudcover cookie file path', :default_value => File.join(ENV['HOME'],'.oktasession')
19
+
20
+ desc 'Simply verify that a set of credentials are valid to login to Okta. Returns 0 on success and non-zero on failure.'
21
+ arg_name '[credential file path]'
22
+ command 'simple-auth' do |c|
23
+ c.switch [:f], :desc => 'Get credentials from file path specified as first argument (Useful for OpenVPN authentication)'
24
+ c.switch [:radius], :desc => 'Return RADIUS style Accept/Reject Messages', :default_value => false
25
+ c.flag [:g, :group], :desc => 'Verify membership to the specified group during authentication', :default_value => false
26
+ c.flag [:c, :context], :desc => 'Extra context for success/fail message', :default_value => false
27
+
28
+ c.action do |global_options,options,args|
29
+ if options[:f]
30
+ raise CredentialFileError, "No readable credential file specified" unless File.readable?(args.first)
31
+ end
32
+
33
+ Cloudcover::SimpleAuth.new(options,args.first).verify_user
34
+
35
+ end
36
+ end
37
+
38
+ pre do |global,command,options,args|
39
+ $verbose = global[:verbose] || global[:debug]
40
+ $debug = global[:debug]
41
+ $config_path = global[:config]
42
+ $color = global[:color]
43
+ true
44
+ end
45
+
46
+ post do |global,command,options,args|
47
+ # Post logic here
48
+ # Use skips_post before a command to skip this
49
+ # block on that command only
50
+ end
51
+
52
+ on_error do |exception|
53
+ # Error logic here
54
+ # return false to skip default error handling
55
+ false
56
+ end
57
+
58
+ exit run(ARGV)
@@ -0,0 +1,29 @@
1
+ # Ensure we require the local version and not one we might have installed already
2
+ require File.join([File.dirname(__FILE__),'lib','cloudcover','version.rb'])
3
+ spec = Gem::Specification.new do |s|
4
+ s.name = 'cloudcover'
5
+ s.version = Cloudcover::VERSION
6
+ s.author = 'Matt Krieger'
7
+ s.email = 'matt.krieger@sportngin.com'
8
+ s.homepage = 'http://www.sportngin.com'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.summary = 'Provides a simple interface for using Okta authentication in command line applications'
11
+ s.files = `git ls-files`.split("
12
+ ")
13
+ s.require_paths << 'lib'
14
+ s.bindir = 'bin'
15
+ s.executables << 'cloudcover'
16
+
17
+ s.add_dependency 'httparty'
18
+ s.add_dependency 'http-cookie'
19
+ s.add_dependency "highline"
20
+ s.add_dependency "terminal-table"
21
+ s.add_dependency "minitar"
22
+ s.add_dependency "hashdiff"
23
+
24
+ s.add_development_dependency 'rake'
25
+ s.add_development_dependency 'rdoc'
26
+
27
+
28
+ s.add_runtime_dependency "gli", "~>2.13.4"
29
+ end
@@ -0,0 +1,107 @@
1
+ module Cloudcover
2
+ class SimpleAuth
3
+
4
+ DEFAULT_CONTEXT = "AUTH"
5
+
6
+ def initialize(opts,path)
7
+ Output.say_debug("SimpleAuth class: #{self}")
8
+ @config = Cloudcover::Config.config
9
+ @okta = Cloudcover::Okta::Client.new
10
+ @credentials = {}
11
+ @opts = opts
12
+ @creds_path = path unless path.nil?
13
+ end
14
+
15
+ def verify_user
16
+ get_credentials
17
+ auth_response(false, "#{formatted_date(Time.now)} - #{context_message} - Access denied, failed login for #{username}") unless login
18
+ if group_id
19
+ auth_response(false,"#{formatted_date(Time.now)} - #{context_message} - Access denied, #{username} is not a member of group ID '#{group_id}'") unless is_valid_group_member
20
+ end
21
+ auth_response(true, "#{formatted_date(Time.now)} - #{context_message} - Access granted for #{username}")
22
+ end
23
+
24
+ def auth_response(auth, msg)
25
+ if auth
26
+ if @opts[:radius]
27
+ p "Accept"
28
+ else
29
+ p msg
30
+ end
31
+ else
32
+ if @opts[:radius]
33
+ abort 'Reject'
34
+ else
35
+ abort msg
36
+ end
37
+ end
38
+ end
39
+
40
+ def get_credentials
41
+ if file_based?
42
+ Output.say_debug("Using credtials from #{@creds_path}")
43
+ creds = file_creds(@creds_path)
44
+ @credentials[:username] = creds.first
45
+ @credentials[:password] = creds.last
46
+ else
47
+ @credentials[:username] = Output.ask("Username: ")
48
+ @credentials[:password] = Output.ask("Password: "){ |q| q.echo = "*" }
49
+ end
50
+ end
51
+
52
+ def file_creds(creds_path)
53
+ credentials = IO.read(creds_path).split rescue {}
54
+ raise InvalidCredsFile unless credentials.length == 2
55
+ credentials
56
+ end
57
+
58
+ def formatted_date(time)
59
+ Time.at(time).strftime(date_format)
60
+ end
61
+
62
+ def username
63
+ @credentials[:username]
64
+ end
65
+
66
+ def password
67
+ @credentials[:password]
68
+ end
69
+
70
+ def login
71
+ @okta.login(username, password)
72
+ if @okta.logged_in?
73
+ @user_id = @okta.login_id
74
+ true
75
+ else
76
+ false
77
+ end
78
+ end
79
+
80
+ def is_valid_group_member
81
+ @okta.groups.map{ |g| g[:id] }.include? group_id
82
+ end
83
+
84
+ def date_format
85
+ @config.has_key?(:date_format) ? @config[:date_format] : "%a %b %e %H:%M:%S %Y"
86
+ end
87
+
88
+ def group_id
89
+ @opts[:group]
90
+ end
91
+
92
+ def file_based?
93
+ @opts[:f]
94
+ end
95
+
96
+ def context
97
+ @opts[:context]
98
+ end
99
+
100
+ def context_message
101
+ context || DEFAULT_CONTEXT
102
+ end
103
+
104
+
105
+ InvalidCredsFile = Class.new(StandardError)
106
+ end
107
+ end
@@ -0,0 +1 @@
1
+ require "cloudcover/commands/simple_auth"
@@ -0,0 +1,36 @@
1
+ require 'yaml'
2
+
3
+ module Cloudcover
4
+ class Config
5
+
6
+ def self.config
7
+ self.new.load_config($config_path)
8
+ end
9
+
10
+ def load_config(file)
11
+ Output.say_debug("Loading the config file from #{file}")
12
+ raise MissingConfig, "Missing configuration file: #{file} Run 'cloudcover help'" unless File.exist?(file)
13
+ @cloudcover_config = symbolize_keys(YAML.load_file(file)) rescue {}
14
+ end
15
+
16
+ # We want all ouf our YAML loaded keys to be symbols
17
+ # taken from http://devblog.avdi.org/2009/07/14/recursively-symbolize-keys/
18
+ def symbolize_keys(hash)
19
+ hash.inject({}){|result, (key, value)|
20
+ new_key = case key
21
+ when String then key.to_sym
22
+ else key
23
+ end
24
+ new_value = case value
25
+ when Hash then symbolize_keys(value)
26
+ else value
27
+ end
28
+ result[new_key] = new_value
29
+ result
30
+ }
31
+ end
32
+
33
+ MissingConfig = Class.new(StandardError)
34
+ MissingEnvironment = Class.new(StandardError)
35
+ end
36
+ end
@@ -0,0 +1,85 @@
1
+ require 'httparty'
2
+ require 'socket'
3
+
4
+ module Cloudcover
5
+ module Okta
6
+ class Client
7
+ include HTTParty
8
+ debug_output if $debug
9
+
10
+ attr_reader :headers
11
+
12
+ def initialize
13
+ @config = Cloudcover::Config.config
14
+ self.class.base_uri "https://#{@config[:okta_domain]}.okta.com"
15
+ @headers = {
16
+ 'Content-Type' => "application/json",
17
+ 'Accept' => "application/json",
18
+ 'User-Agent' => "Cloudcover/#{Cloudcover::VERSION} (#{Socket.gethostname})"
19
+ }
20
+ end
21
+
22
+ def self.login(username, password)
23
+ new.tap { |instance| instance.login(username, password) }
24
+ end
25
+
26
+ def set_headers(headers)
27
+ @headers.merge!(headers)
28
+ end
29
+
30
+ def remove_header(key)
31
+ @headers.delete(key)
32
+ end
33
+
34
+ def get_json(path, options = {})
35
+ JSON.parse(self.class.get(path, options).body, symbolize_names: true)
36
+ end
37
+
38
+ def me
39
+ get_json('/api/v1/users/me', headers: @headers)
40
+ end
41
+
42
+ def groups
43
+ get_json('/api/v1/users/me/groups', headers: @headers)
44
+ end
45
+
46
+ def login_id
47
+ me[:profile][:login]
48
+ end
49
+
50
+ def logged_in?
51
+ me[:status] == "ACTIVE"
52
+ rescue
53
+ false
54
+ end
55
+
56
+ def login(username, password)
57
+ post_body = {username: username, password: password}.to_json
58
+ resp = self.class.post('/api/v1/sessions?additionalFields=cookieToken', {body: post_body, headers: @headers})
59
+ if resp.parsed_response['status'] == "ACTIVE"
60
+ set_session_cookie(resp.parsed_response['cookieToken'])
61
+ else
62
+ resp.parsed_response
63
+ end
64
+ end
65
+
66
+ def test_get(path)
67
+ self.class.get(path, headers: @headers)
68
+ end
69
+
70
+ def set_session_cookie(cookie_token)
71
+ resp = self.class.get("/login/sessionCookie?token=#{cookie_token}", headers: @headers)
72
+ @headers['Cookie'] = parse_cookie(resp.headers).to_cookie_string
73
+ end
74
+ private :set_session_cookie
75
+
76
+ def parse_cookie(resp_cookie)
77
+ cookie_hash = CookieHash.new
78
+ resp_cookie.get_fields('Set-Cookie').each { |c| cookie_hash.add_cookies(c) }
79
+ cookie_hash
80
+ end
81
+ private :parse_cookie
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1 @@
1
+ require "cloudcover/okta/client"
@@ -0,0 +1,48 @@
1
+ require 'highline'
2
+
3
+ module Cloudcover
4
+ module Output
5
+ def self.terminal
6
+ HighLine.color_scheme = color_scheme
7
+ @terminal ||= HighLine.new
8
+ end
9
+
10
+ def self.color_scheme
11
+ @color_scheme ||= HighLine::ColorScheme.new(
12
+ :normal => [],
13
+ :error => [:bold, :red],
14
+ :warning => [:bold, :yellow],
15
+ :verbose => [:bold, :magenta],
16
+ :debug => [:bold, :cyan],
17
+ :success => [:bold, :green],
18
+ :addition => [:bold, :green],
19
+ :removal => [:bold, :red],
20
+ :modification => [:bold, :yellow],
21
+ )
22
+ end
23
+
24
+ def self.say(msg, log_style=:normal)
25
+ terminal.say format(msg, log_style)
26
+ end
27
+
28
+ def self.format(msg, log_style=:normal)
29
+ if $color
30
+ terminal.color(msg.to_s, log_style)
31
+ else
32
+ msg
33
+ end
34
+ end
35
+
36
+ def self.say_verbose(msg)
37
+ terminal.say format(msg.to_s, 'verbose') if $verbose
38
+ end
39
+
40
+ def self.say_debug(msg, log_style=:debug)
41
+ terminal.say format(msg.to_s, log_style) if $debug
42
+ end
43
+
44
+ def self.ask(*args, &block)
45
+ terminal.ask(*args, &block)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module Cloudcover
2
+ VERSION = '0.0.1'
3
+ end
data/lib/cloudcover.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "cloudcover/version"
2
+ require "cloudcover/output"
3
+
4
+ require "cloudcover/config"
5
+ require "cloudcover/okta"
6
+
7
+ require "cloudcover/commands"
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudcover
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Matt Krieger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
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'
27
+ - !ruby/object:Gem::Dependency
28
+ name: http-cookie
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: highline
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'
55
+ - !ruby/object:Gem::Dependency
56
+ name: terminal-table
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitar
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'
83
+ - !ruby/object:Gem::Dependency
84
+ name: hashdiff
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rdoc
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'
125
+ - !ruby/object:Gem::Dependency
126
+ name: gli
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 2.13.4
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 2.13.4
139
+ description:
140
+ email: matt.krieger@sportngin.com
141
+ executables:
142
+ - cloudcover
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".ruby-version"
148
+ - Gemfile
149
+ - Gemfile.lock
150
+ - README.md
151
+ - Rakefile
152
+ - bin/cloudcover
153
+ - cloudcover.gemspec
154
+ - lib/cloudcover.rb
155
+ - lib/cloudcover/commands.rb
156
+ - lib/cloudcover/commands/simple_auth.rb
157
+ - lib/cloudcover/config.rb
158
+ - lib/cloudcover/okta.rb
159
+ - lib/cloudcover/okta/client.rb
160
+ - lib/cloudcover/output.rb
161
+ - lib/cloudcover/version.rb
162
+ homepage: http://www.sportngin.com
163
+ licenses: []
164
+ metadata: {}
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ requirements: []
181
+ rubyforge_project:
182
+ rubygems_version: 2.4.8
183
+ signing_key:
184
+ specification_version: 4
185
+ summary: Provides a simple interface for using Okta authentication in command line
186
+ applications
187
+ test_files: []
188
+ has_rdoc: