gds-sso 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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