cloudcover 0.0.1

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: 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: