sinatra-els 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ba66d68fec95409ea3060da53d24672033ed54d8
4
+ data.tar.gz: 316f7cc35abd3ccc780a3b68622c241e5bb1e7ec
5
+ SHA512:
6
+ metadata.gz: 3c1507750818d74b9bfd6bbfa26a760d8c4aa9c625fecb7f45e871889f7d21749fb4019c71da38ec0acf6c0cd3b5f6ded728c34255da1d1a14ccc29ceb91ae37
7
+ data.tar.gz: 8edab93b0fb5d522cf167dab07fbac928fda1bfc2cd7f3d7e69be153624ea885ed6b38ff87950ab9204064025fcfe23023dec1cdd92f26d57083815bea14976e
@@ -0,0 +1,113 @@
1
+ # Sinatra ELS Helper
2
+
3
+ This is a Sinatra extension to assist in verification of an ELS (openAM) authentication token.
4
+
5
+ These tokens are usually stored in a browser cookie to assist in SSO but we can also use them
6
+ to create Web Services with federated authentication. The caller must first authenticate
7
+ with ELS to generate a token then pass that token along with a WS call (usually in a HTTP Header)
8
+
9
+ To find out more about generating a token, see [https://stash.ops.aol.com/projects/CIO_CODEHAUS_PUBLIC/repos/els_token/browse]
10
+
11
+ ## Installation
12
+
13
+ Bung this in your Gemfile
14
+
15
+ gem 'sinatra-els', '~>1.0.0'
16
+
17
+
18
+ There are two flavors of Sinatra applications, classic and modular. Both need a require statement:
19
+
20
+ require 'sinatra/els'
21
+
22
+ That's it for classic apps. Modular apps must register the extension:
23
+
24
+ class MyApp < Sinatra::Base
25
+ register Sinatra::ELS
26
+ end
27
+
28
+ ## Usage
29
+
30
+ There are a couple of ways to use this extension:
31
+
32
+ 1. els_before hook
33
+
34
+ The els_before hook, without any arguments, will setup a Sinatra before handler for all routes and interrogate for ELS authentication.
35
+
36
+ the els_before method takes an optional hash which can specify an :only or :except key with an array of strings that represent regaulr expressions (without the enclosing '/' slashes). These will be used to match the route and invoke ELS authentication. As the key names suggest, regular expressions passed to the :only key will only invoke ELS authentication when the current route matches. Converseley, the :except key will be used to ignore ELS authentication for the supplied regex's.
37
+
38
+ Example 1: Only process ELS authentication on the '/api/' route and any route ending with 'reports'
39
+
40
+ els_before :only => [ "^\/api\/", "reports$" ]
41
+
42
+ Example 2: Perform ELS authentication on all routes except '/util/'
43
+
44
+ els_before :except => [ "^\/util\/" ]
45
+
46
+
47
+ 2. authorize!
48
+
49
+ The _authorize!_ method (used by els_before) can be manually invoked in any route should the els_before hook not be required or if the default behavior of els_before doesn't meet your needs
50
+
51
+ Example:
52
+
53
+ get '/myapi' do
54
+ authorize!
55
+ # Code below will be executed if authentication is successful
56
+ end
57
+
58
+
59
+ ###Environment specific setup
60
+
61
+ This is just something I have found useful during development and testing. Because the default is to NOT use ELS, it's possible to selectively setup ELS depending on your environment.
62
+
63
+ Example: Only use the els_before hook in production and uat environments
64
+
65
+ configure :production, :uat do
66
+ els_before
67
+ end
68
+
69
+ ### Configuration
70
+
71
+ This extension requires a configuration object (as a hash) which will tell it the ELS end point to use, the AD Users and/or AD Groups to allow when performing credential validation and the HTTP header key in which to expect an ELS identity token. For the sake of this example I have stored my config in a .yml file
72
+
73
+ __yml file: /config/els.yml__
74
+
75
+ development:
76
+ uri: https://els-sso.corp.aol.com/opensso/identity
77
+ users:
78
+ - bob
79
+ - alice
80
+ groups:
81
+ - MyApi users
82
+ - Domain Admins
83
+ header: X-API-Key
84
+
85
+ This must be loaded, under the environment key, to :els_opts.
86
+
87
+ The following is a full example
88
+
89
+ __app file: /app/my_api.rb___
90
+
91
+ class MyApi < Sinatra::Base
92
+
93
+ set :root, File.expand_path(File.join(File.dirname(__FILE__), '..'))
94
+
95
+ register Sinatra::ELS
96
+
97
+ set :els_opts, YAML.load_file(File.join(settings.root, 'config','els.yml'))[settings.environment.to_s]
98
+
99
+ configure :production, :uat do
100
+ els_before :except => [ "\/util/" ]
101
+ end
102
+
103
+ # ELS validation will occur before this route in production and uat
104
+ get '/api/coolness' do
105
+ "Cool! You are allowed to use this"
106
+ end
107
+
108
+ # ELS validation will NOT occur before this route in any environment
109
+ get '/util/health' do
110
+ "All good, carry on"
111
+ end
112
+
113
+ end
@@ -0,0 +1,101 @@
1
+ require 'sinatra/base'
2
+ require 'els_token'
3
+ require 'yaml'
4
+
5
+
6
+ module Sinatra
7
+ module ELS
8
+
9
+ module Auth
10
+ #
11
+ # Set up the before hook to use ELS authentication.
12
+ # Setup ELS options using <i>set :els_opts</i>
13
+ #
14
+ # params:
15
+ # opts - Optional hash with a key of either :only, or :except
16
+ # and an array of String values which will be cast into
17
+ # regular expressions.
18
+ #
19
+ # example:
20
+ # # only use els when patch matches "/api/" or anything ending in "/orders"
21
+ # els_before true, :only => ["^\/api\/",".*\/orders$"]
22
+ #
23
+ # # do not use els if the "/util/" path is matched
24
+ # els_before true, :except
25
+ #
26
+ # # use els before everything
27
+ # els_before
28
+ #
29
+ # when <i>before_all === false</i> all before processing will be ignored
30
+ #
31
+ # An optional hash of path matchers can be supplied
32
+ #
33
+ def els_before(opts = {})
34
+ before {
35
+ if opts.key? :only
36
+ # execute authorize if path matches regex(s)
37
+ if request.path_info.match(/#{opts[:only].map{|i|"(#{i})"}.join('|')}/)
38
+ authorize!
39
+ end
40
+ elsif opts.key? :except
41
+ # execute authorize if path doesn't match regex(s)
42
+ if not request.path_info.match(/#{opts[:except].map{|i|"(#{i})"}.join('|')}/)
43
+ authorize!
44
+ end
45
+ else
46
+ authorize!
47
+ end
48
+ }
49
+ end
50
+ end
51
+
52
+ module Helpers
53
+
54
+ #
55
+ # Perform ELS authentication
56
+ # Setup ELS options using <i>set :els_opts</i>
57
+ #
58
+ def authorize!
59
+ token = env[settings.els_opts['header']]
60
+ headers "X-Resource" => request.request_method + " : " + request.url
61
+ unless token
62
+ logger.warn("Missing #{settings.els_opts['header']} from IP Address: #{env['REMOTE_ADDR']}")
63
+ halt 403
64
+ else
65
+ unless ElsToken.is_token_valid?(token, settings.els_opts)
66
+ logger.warn("failed authentication from IP Address: #{env['REMOTE_ADDR']}")
67
+ halt 403
68
+ else
69
+ user = ElsToken.get_identity(token, settings.els_opts)
70
+ # Ensure user has explicit permission via username or group association
71
+ skip_user = settings.els_opts['users'].nil?
72
+ skip_group = settings.els_opts['groups'].nil?
73
+ user_missing = group_missing = false
74
+ unless skip_user
75
+ user_missing = !settings.els_opts['users'].include?(user.name)
76
+ end
77
+ unless skip_group
78
+ group_missing = (settings.els_opts['groups'] & user.roles).empty?
79
+ end
80
+ if user_missing and group_missing
81
+ logger.warn("#{user.name} Does not have permission to use this servce: #{env['REMOTE_ADDR']}")
82
+ halt 403
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ # TODO - other interesting els routes
89
+ end
90
+
91
+ def self.registered(app)
92
+ app.helpers ELS::Helpers
93
+ app.register ELS::Auth
94
+
95
+ # When including, set the els_opts hash. eg.
96
+ #app.set :els_opts, YAML.load_file(File.join(app.settings.root, 'config','els.yml'))[app.settings.environment.to_s]
97
+ end
98
+ end
99
+
100
+ register ELS
101
+ end
@@ -0,0 +1,23 @@
1
+ require 'sinatra/base'
2
+ require 'logger'
3
+ require 'sinatra/els'
4
+
5
+ class Tester < Sinatra::Base
6
+ set :root, File.expand_path(File.join(File.dirname(__FILE__), '..'))
7
+
8
+ register Sinatra::ELS
9
+
10
+ set :els_opts, YAML.load_file(File.join(settings.root, 'config','els.yml'))[settings.environment.to_s]
11
+
12
+ els_before :only => ["^\/auth"]
13
+
14
+ get '/no_auth' do
15
+ "It works!"
16
+ end
17
+
18
+ get '/auth' do
19
+ "It works!"
20
+ end
21
+
22
+ end
23
+
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'els_token'
3
+ require 'yaml'
4
+
5
+ describe Tester do
6
+ include Rack::Test::Methods
7
+
8
+ before :all do
9
+ # obtain a valid els token
10
+ puts "Please provide a valid user which is contained in the els.yml file"
11
+ username = gets.chomp
12
+ puts "Please enter your password"
13
+ password = STDIN.noecho(&:gets).chomp
14
+ els = YAML.load_file(File.join(File.dirname(__FILE__),'..', 'config','els.yml'))["test"]
15
+ @token = ElsToken.authenticate(username,password,els)
16
+ end
17
+
18
+ def app
19
+ Tester
20
+ end
21
+
22
+ context 'ELS Not Required' do
23
+ it 'should not return 403' do
24
+ get '/no_auth'
25
+ expect(last_response).to be_ok
26
+ end
27
+ end
28
+
29
+ context 'ELS Required' do
30
+
31
+ it 'should return 403 with no els token' do
32
+ get '/auth'
33
+ expect(last_response.status).to eql(403)
34
+ end
35
+
36
+ it 'should return 200 with els token' do
37
+ get '/auth', nil, 'X-API-Key' => "#{@token}"
38
+ expect(last_response).to be_ok
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,20 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ app_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
4
+ $: << File.join(app_root, 'lib')
5
+
6
+ require 'app'
7
+ require 'rspec'
8
+ require 'rack/test'
9
+
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+
15
+ # Run specs in random order to surface order dependencies. If you find an
16
+ # order dependency and want to debug it, you can fix the order by providing
17
+ # the seed, which is printed after each run.
18
+ # --seed 1234
19
+ config.order = 'random'
20
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-els
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Neil Chambers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
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: rack-test
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: els_token
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.2.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: sinatra
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.4.4
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.4.4
69
+ description: See README.md
70
+ email: neil.chambers@teamaol.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files:
74
+ - README.md
75
+ files:
76
+ - lib/sinatra/els.rb
77
+ - README.md
78
+ - spec/app.rb
79
+ - spec/app_spec.rb
80
+ - spec/spec_helper.rb
81
+ homepage: https://stash.ops.aol.com/projects/CIOCODEHAUS/repos/sinatra-els/browse
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options:
87
+ - --title
88
+ - Sinatra ELS Helper
89
+ - --main
90
+ - README.md
91
+ - --line-numbers
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.1.1
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: ELS helper for Sinatra
110
+ test_files:
111
+ - spec/app.rb
112
+ - spec/app_spec.rb
113
+ - spec/spec_helper.rb