gds-sso 0.1.1 → 0.3.0

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.
data/README.md CHANGED
@@ -23,11 +23,17 @@ Create a `config/initializers/gds-sso.rb` that looks like:
23
23
 
24
24
  GDS::SSO.config do |config|
25
25
  config.user_model = 'User'
26
+
26
27
  # set up ID and Secret in a way which doesn't require it to be checked in to source control...
27
28
  config.oauth_id = ENV['OAUTH_ID']
28
29
  config.oauth_secret = ENV['OAUTH_SECRET']
30
+
29
31
  # optional config for location of sign-on-o-tron
30
32
  config.oauth_root_url = "http://localhost:3001"
33
+
34
+ # optional config for API Access (requests which accept application/json)
35
+ config.basic_auth_user = 'api'
36
+ config.basic_auth_password = 'secret'
31
37
  end
32
38
 
33
39
  The user model needs to respond to klass.find_by_uid(uid), and must include the GDS::SSO::User module.
@@ -10,31 +10,35 @@ module GDS
10
10
  autoload :FailureApp, 'gds-sso/failure_app'
11
11
  autoload :ControllerMethods, 'gds-sso/controller_methods'
12
12
  autoload :User, 'gds-sso/user'
13
+ autoload :ApiAccess, 'gds-sso/api_access'
14
+
15
+ # User to return as logged in during tests
16
+ mattr_accessor :test_user
13
17
 
14
18
  def self.config
15
19
  yield GDS::SSO::Config
16
20
  end
17
21
 
18
- def self.default_strategy
19
- if ['development', 'test'].include?(Rails.env) && ENV['GDS_SSO_STRATEGY'] != 'real'
20
- :mock_gds_sso
21
- else
22
- :gds_sso
23
- end
24
- end
25
-
26
22
  class Engine < ::Rails::Engine
27
23
  # Force routes to be loaded if we are doing any eager load.
28
24
  # TODO - check this one - Stolen from Devise because it looked sensible...
29
25
  config.before_eager_load { |app| app.reload_routes! }
30
-
26
+
31
27
  config.app_middleware.use ::OmniAuth::Builder do
32
28
  provider :gds, GDS::SSO::Config.oauth_id, GDS::SSO::Config.oauth_secret
33
29
  end
34
30
 
35
- config.app_middleware.use Warden::Manager do |manager|
36
- manager.default_strategies GDS::SSO.default_strategy
37
- manager.failure_app = GDS::SSO::FailureApp
31
+ def self.use_mock_strategies?
32
+ ['development', 'test'].include?(Rails.env) && ENV['GDS_SSO_STRATEGY'] != 'real'
33
+ end
34
+
35
+ def self.default_strategies
36
+ use_mock_strategies? ? [:mock_gds_sso, :mock_gds_sso_api_access] : [:gds_sso, :gds_sso_api_access]
37
+ end
38
+
39
+ config.app_middleware.use Warden::Manager do |config|
40
+ config.default_strategies *self.default_strategies
41
+ config.failure_app = GDS::SSO::FailureApp
38
42
  end
39
43
  end
40
44
  end
@@ -0,0 +1,12 @@
1
+ require 'rack/accept'
2
+
3
+ module GDS
4
+ module SSO
5
+ class ApiAccess
6
+ def self.api_call?(env)
7
+ request = Rack::Accept::Request.new(env)
8
+ request.best_media_type(%w{application/json text/html}) == 'application/json'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -15,6 +15,13 @@ module GDS
15
15
  mattr_accessor :oauth_root_url
16
16
  @@oauth_root_url = "http://localhost:3001"
17
17
 
18
+ # Basic Auth Credentials (for api access when request accept
19
+ # header is application/json)
20
+ mattr_accessor :basic_auth_user
21
+ mattr_accessor :basic_auth_password
22
+ mattr_accessor :basic_auth_realm
23
+ @@basic_auth_realm = "API Access"
24
+
18
25
  def self.user_klass
19
26
  user_model.to_s.constantize
20
27
  end
@@ -9,14 +9,13 @@ module GDS
9
9
  include ActionController::RackDelegation
10
10
  include ActionController::UrlFor
11
11
  include ActionController::Redirecting
12
+ include ActionController::HttpAuthentication::Basic::ControllerMethods
12
13
  include Rails.application.routes.url_helpers
13
14
 
14
15
  def self.call(env)
15
- action(:respond).call(env)
16
- end
17
-
18
- def respond
19
- redirect
16
+ if ! ::GDS::SSO::ApiAccess.api_call?(env)
17
+ action(:redirect).call(env)
18
+ end
20
19
  end
21
20
 
22
21
  def redirect
@@ -33,6 +32,7 @@ module GDS
33
32
  def store_location!
34
33
  session["return_to"] = env['warden.options'][:attempted_path] if request.get?
35
34
  end
35
+
36
36
  end
37
37
  end
38
38
  end
@@ -8,6 +8,7 @@ require 'multi_json'
8
8
  # use OmniAuth::Builder :gds, 'API Key', 'Secret Key'
9
9
 
10
10
  class OmniAuth::Strategies::Gds < OmniAuth::Strategies::OAuth2
11
+
11
12
  # @param [Rack Application] app standard middleware application parameter
12
13
  # @param [String] api_key the application id as [provided by GDS]
13
14
  # @param [String] secret_key the application secret as [provided by Bitly]
@@ -16,12 +17,23 @@ class OmniAuth::Strategies::Gds < OmniAuth::Strategies::OAuth2
16
17
  :site => "#{GDS::SSO::Config.oauth_root_url}/",
17
18
  :authorize_url => "#{GDS::SSO::Config.oauth_root_url}/oauth/authorize",
18
19
  :token_url => "#{GDS::SSO::Config.oauth_root_url}/oauth/access_token",
19
- :access_token_url => "#{GDS::SSO::Config.oauth_root_url}/oauth/access_token"
20
+ :access_token_url => "#{GDS::SSO::Config.oauth_root_url}/oauth/access_token",
21
+ :ssl => {
22
+ :verify => false
23
+ }
20
24
  }
21
25
 
22
26
  super(app, :gds, api_key, secret_key, client_options, options, &block)
23
27
  end
24
28
 
29
+ def call(env)
30
+ if GDS::SSO::ApiAccess.api_call?(env)
31
+ @app.call(env)
32
+ else
33
+ super
34
+ end
35
+ end
36
+
25
37
  protected
26
38
 
27
39
  def fetch_user_data
@@ -0,0 +1,5 @@
1
+ module GDS
2
+ module SSO
3
+ VERSION = "0.3.0"
4
+ end
5
+ end
@@ -2,7 +2,7 @@ require 'warden'
2
2
  require 'omniauth/oauth'
3
3
 
4
4
  Warden::Manager.serialize_into_session do |user|
5
- user.uid
5
+ user.respond_to?(:uid) ? user.uid : nil
6
6
  end
7
7
 
8
8
  Warden::Manager.serialize_from_session do |uid|
@@ -11,10 +11,12 @@ end
11
11
 
12
12
  Warden::Strategies.add(:gds_sso) do
13
13
  def valid?
14
- true
14
+ ! ::GDS::SSO::ApiAccess.api_call?(env)
15
15
  end
16
16
 
17
17
  def authenticate!
18
+ Rails.logger.debug("Authenticating with gds_sso strategy")
19
+
18
20
  if request.env['omniauth.auth'].nil?
19
21
  fail!("No credentials, bub")
20
22
  else
@@ -32,12 +34,69 @@ Warden::Strategies.add(:gds_sso) do
32
34
  end
33
35
  end
34
36
 
37
+ Warden::Strategies.add(:gds_sso_api_access) do
38
+ def valid?
39
+ ::GDS::SSO::ApiAccess.api_call?(env)
40
+ end
41
+
42
+ def authenticate!
43
+ Rails.logger.debug("Authenticating with gds_sso_api_access strategy")
44
+
45
+ auth = Rack::Auth::Basic::Request.new(env)
46
+
47
+ return custom!(unauthorized) unless auth.provided?
48
+ return fail!(:bad_request) unless auth.basic?
49
+
50
+ if valid_api_user?(*auth.credentials)
51
+ success!(auth.credentials[0])
52
+ else
53
+ custom!(unauthorized)
54
+ end
55
+ end
56
+
57
+ def valid_api_user?(username, password)
58
+ username.to_s.strip != '' &&
59
+ password.to_s.strip != '' &&
60
+ username == ::GDS::SSO::Config.basic_auth_user &&
61
+ password == ::GDS::SSO::Config.basic_auth_password
62
+ end
63
+
64
+ def unauthorized
65
+ [
66
+ 401,
67
+ {
68
+ 'Content-Type' => 'text/plain',
69
+ 'Content-Length' => '0',
70
+ 'WWW-Authenticate' => %(Basic realm="#{GDS::SSO::Config.basic_auth_realm}")
71
+ },
72
+ []
73
+ ]
74
+ end
75
+ end
76
+
35
77
  Warden::Strategies.add(:mock_gds_sso) do
36
78
  def valid?
37
- true
79
+ ! ::GDS::SSO::ApiAccess.api_call?(env)
80
+ end
81
+
82
+ def authenticate!
83
+ Rails.logger.debug("Authenticating with mock_gds_sso strategy")
84
+ test_user = GDS::SSO.test_user || GDS::SSO::Config.user_klass.first
85
+ if test_user
86
+ success!(test_user)
87
+ else
88
+ raise "GDS-SSO running in mock mode and no test user found. Normally we'd load the first user in the database. Create a user in the database."
89
+ end
38
90
  end
91
+ end
39
92
 
93
+ Warden::Strategies.add(:mock_gds_sso_api_access) do
94
+ def valid?
95
+ ::GDS::SSO::ApiAccess.api_call?(env)
96
+ end
97
+
40
98
  def authenticate!
41
- success!(GDS::SSO::Config.user_klass.first)
99
+ Rails.logger.debug("Authenticating with mock_gds_sso_api_access strategy")
100
+ success!(GDS::SSO.test_user || GDS::SSO::Config.user_klass.first)
42
101
  end
43
102
  end
@@ -5,17 +5,24 @@ require 'gds-sso/omniauth_strategy'
5
5
 
6
6
  class TestOmniAuthStrategy < Test::Unit::TestCase
7
7
  def setup
8
- @strategy = OmniAuth::Strategies::Gds.new(:gds, 'client_id', 'client_secret')
8
+ @app = stub("app")
9
+ @strategy = OmniAuth::Strategies::Gds.new(@app, :gds, 'client_id', 'client_secret')
9
10
  @strategy.stubs(:fetch_user_data).returns({'user' => {'uid' => 'abcde', 'version' => 1, 'name' => 'Matt Patterson', 'email' => 'matt@alphagov.co.uk', 'github' => 'fidothe', 'twitter' => 'fidothe'}}.to_json)
10
11
  end
11
12
 
12
- def test_basic_auth_hash_structure
13
+ def test_build_auth_hash_returns_name_and_email
13
14
  assert_equal 'Matt Patterson', @strategy.send(:build_auth_hash)['user_info']['name']
14
15
  assert_equal 'matt@alphagov.co.uk', @strategy.send(:build_auth_hash)['user_info']['email']
15
16
  end
16
17
 
17
- def test_extra_auth_hash_structure
18
+ def test_build_auth_hash_contains_extra_info
18
19
  expected = {'uid' => 'abcde', 'version' => 1, 'name' => 'Matt Patterson', 'email' => 'matt@alphagov.co.uk', 'github' => 'fidothe', 'twitter' => 'fidothe'}
19
20
  assert_equal expected, @strategy.send(:build_auth_hash)['extra']['user_hash']
20
21
  end
22
+
23
+ def test_oauth_bypassed_if_json_is_accepted_by_request
24
+ @app.expects(:call)
25
+ rack_env = { "HTTP_ACCEPT" => 'application/json' }
26
+ @strategy.call(rack_env)
27
+ end
21
28
  end
metadata CHANGED
@@ -1,108 +1,125 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: gds-sso
3
- version: !ruby/object:Gem::Version
4
- version: 0.1.1
3
+ version: !ruby/object:Gem::Version
5
4
  prerelease:
5
+ version: 0.3.0
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Matt Patterson
9
9
  - James Stewart
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-11-02 00:00:00.000000000Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
13
+
14
+ date: 2012-01-10 00:00:00 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
16
17
  name: rails
17
- requirement: &70169822136140 !ruby/object:Gem::Requirement
18
+ requirement: &id001 !ruby/object:Gem::Requirement
18
19
  none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
22
23
  version: 3.0.0
23
24
  type: :runtime
24
25
  prerelease: false
25
- version_requirements: *70169822136140
26
- - !ruby/object:Gem::Dependency
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
27
28
  name: warden
28
- requirement: &70169822135760 !ruby/object:Gem::Requirement
29
+ requirement: &id002 !ruby/object:Gem::Requirement
29
30
  none: false
30
- requirements:
31
- - - ! '>='
32
- - !ruby/object:Gem::Version
33
- version: '0'
31
+ requirements:
32
+ - - "="
33
+ - !ruby/object:Gem::Version
34
+ version: 1.0.6
34
35
  type: :runtime
35
36
  prerelease: false
36
- version_requirements: *70169822135760
37
- - !ruby/object:Gem::Dependency
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
38
39
  name: oauth2
39
- requirement: &70169822135260 !ruby/object:Gem::Requirement
40
+ requirement: &id003 !ruby/object:Gem::Requirement
40
41
  none: false
41
- requirements:
42
- - - =
43
- - !ruby/object:Gem::Version
42
+ requirements:
43
+ - - "="
44
+ - !ruby/object:Gem::Version
44
45
  version: 0.4.1
45
46
  type: :runtime
46
47
  prerelease: false
47
- version_requirements: *70169822135260
48
- - !ruby/object:Gem::Dependency
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
49
50
  name: oa-oauth
50
- requirement: &70169822134800 !ruby/object:Gem::Requirement
51
+ requirement: &id004 !ruby/object:Gem::Requirement
51
52
  none: false
52
- requirements:
53
- - - =
54
- - !ruby/object:Gem::Version
53
+ requirements:
54
+ - - "="
55
+ - !ruby/object:Gem::Version
55
56
  version: 0.2.6
56
57
  type: :runtime
57
58
  prerelease: false
58
- version_requirements: *70169822134800
59
- - !ruby/object:Gem::Dependency
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
60
61
  name: oa-core
61
- requirement: &70169822134340 !ruby/object:Gem::Requirement
62
+ requirement: &id005 !ruby/object:Gem::Requirement
62
63
  none: false
63
- requirements:
64
- - - =
65
- - !ruby/object:Gem::Version
64
+ requirements:
65
+ - - "="
66
+ - !ruby/object:Gem::Version
66
67
  version: 0.2.6
67
68
  type: :runtime
68
69
  prerelease: false
69
- version_requirements: *70169822134340
70
- - !ruby/object:Gem::Dependency
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: rack-accept
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 0.4.4
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
71
83
  name: rake
72
- requirement: &70169822133880 !ruby/object:Gem::Requirement
84
+ requirement: &id007 !ruby/object:Gem::Requirement
73
85
  none: false
74
- requirements:
86
+ requirements:
75
87
  - - ~>
76
- - !ruby/object:Gem::Version
88
+ - !ruby/object:Gem::Version
77
89
  version: 0.9.2
78
90
  type: :development
79
91
  prerelease: false
80
- version_requirements: *70169822133880
81
- - !ruby/object:Gem::Dependency
92
+ version_requirements: *id007
93
+ - !ruby/object:Gem::Dependency
82
94
  name: mocha
83
- requirement: &70169822133420 !ruby/object:Gem::Requirement
95
+ requirement: &id008 !ruby/object:Gem::Requirement
84
96
  none: false
85
- requirements:
97
+ requirements:
86
98
  - - ~>
87
- - !ruby/object:Gem::Version
99
+ - !ruby/object:Gem::Version
88
100
  version: 0.9.0
89
101
  type: :development
90
102
  prerelease: false
91
- version_requirements: *70169822133420
103
+ version_requirements: *id008
92
104
  description: Client for GDS' OAuth 2-based SSO
93
- email:
105
+ email:
94
106
  - matt@constituentparts.com
95
107
  - james.stewart@digital.cabinet-office.gov.uk
96
108
  executables: []
109
+
97
110
  extensions: []
111
+
98
112
  extra_rdoc_files: []
99
- files:
113
+
114
+ files:
115
+ - lib/gds-sso/api_access.rb
100
116
  - lib/gds-sso/config.rb
101
117
  - lib/gds-sso/controller_methods.rb
102
118
  - lib/gds-sso/failure_app.rb
103
119
  - lib/gds-sso/omniauth_strategy.rb
104
120
  - lib/gds-sso/routes.rb
105
121
  - lib/gds-sso/user.rb
122
+ - lib/gds-sso/version.rb
106
123
  - lib/gds-sso/warden_config.rb
107
124
  - lib/gds-sso.rb
108
125
  - README.md
@@ -113,29 +130,38 @@ files:
113
130
  - test/test_user.rb
114
131
  homepage: https://github.com/alphagov/gds-sso
115
132
  licenses: []
133
+
116
134
  post_install_message:
117
135
  rdoc_options: []
118
- require_paths:
136
+
137
+ require_paths:
119
138
  - lib
120
- required_ruby_version: !ruby/object:Gem::Requirement
139
+ required_ruby_version: !ruby/object:Gem::Requirement
121
140
  none: false
122
- requirements:
123
- - - ! '>='
124
- - !ruby/object:Gem::Version
125
- version: '0'
126
- required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ hash: -376516686123011262
145
+ segments:
146
+ - 0
147
+ version: "0"
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
149
  none: false
128
- requirements:
129
- - - ! '>='
130
- - !ruby/object:Gem::Version
131
- version: '0'
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ hash: -376516686123011262
154
+ segments:
155
+ - 0
156
+ version: "0"
132
157
  requirements: []
158
+
133
159
  rubyforge_project: gds-sso
134
- rubygems_version: 1.8.10
160
+ rubygems_version: 1.8.13
135
161
  signing_key:
136
162
  specification_version: 3
137
163
  summary: Client for GDS' OAuth 2-based SSO
138
- test_files:
164
+ test_files:
139
165
  - test/test_helper.rb
140
166
  - test/test_omniauth_strategy.rb
141
167
  - test/test_user.rb