nginx_omniauth_adapter 0.2.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: da45545a31a51031b94607551c7296f3011c3769
4
- data.tar.gz: 79f17b771dffb86ff9527b78a7fbbe14d1a71bf1
2
+ SHA256:
3
+ metadata.gz: 66f14d6c854ca770e18ee0898ed71488b40d74dca518e543035cef0940d9f228
4
+ data.tar.gz: 23e54318a5efbd0f6dd2b020b4454d16b8e6f847982d9a379256244e48edbdc9
5
5
  SHA512:
6
- metadata.gz: 84be2b3d973d457a98b52ba75498b3dd84557012dd8fc9ddadeb5e2873fd9a80efb146f2177024214eadbaf1524814869f250c5ce972fce3e5bad3f61aad7714
7
- data.tar.gz: 432c64e9ec6b1953947d6a8ed72e6c4eb019db5cf984cd62de39361c4d594ca7800be2686f25caae168c9b14f5ec24ccf8ae58ff951916ab049129a613687a6d
6
+ metadata.gz: f893093f330d8b3cbacec6d3a1366f44da12cc0fe9eb75b68f0c2ff075ba7cdeb6c0a71a52e4d4283642562e8c6b4b79f7378b490bc78d2eea1668374617fbc8
7
+ data.tar.gz: bb19421a7885cfa989da7fdb84ee88246efa55662fd05438aeb17c608631a018445eb9e98d500434e41f0fff9f9f3e4275af053a556bf7c3ad9a9c14a1bc5c95
@@ -0,0 +1,78 @@
1
+ name: ci
2
+ on:
3
+ pull_request:
4
+ branches: [master]
5
+ push:
6
+ branches: [master, ci-test]
7
+
8
+ env:
9
+ DOCKER_REPO: 'sorah/acmesmith'
10
+
11
+ jobs:
12
+ test:
13
+ name: rspec
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ ruby-version: ['2.7', '3.0', '3.1']
19
+ container:
20
+ image: public.ecr.aws/sorah/ruby:${{ matrix.ruby-version }}-dev
21
+ steps:
22
+ - name: Cache bundled gems
23
+ uses: actions/cache@v3
24
+ id: rspec-bundle
25
+ with:
26
+ path: ~/bundle
27
+ key: ${{ runner.os }}-${{ matrix.ruby-version }}
28
+ - uses: actions/checkout@v3
29
+ - run: 'apt-get update && apt-get install -y --no-install-recommends nginx'
30
+ - run: 'bundle install --path ~/bundle'
31
+ - run: 'bundle exec rspec -fd'
32
+
33
+ #docker-build:
34
+ # name: docker-build
35
+ # runs-on: ubuntu-latest
36
+ # steps:
37
+ # - uses: actions/checkout@master
38
+ # - run: 'echo $GITHUB_SHA > REVISION'
39
+
40
+ # - run: "docker pull ${DOCKER_REPO}:latest || :"
41
+ # - name: "docker tag ${DOCKER_REPO}:${TAG} ${DOCKER_REPO}:latest"
42
+ # run: |
43
+ # TAG=$(basename "${{ github.ref }}")
44
+ # docker pull ${DOCKER_REPO}:${TAG} || :
45
+ # docker tag ${DOCKER_REPO}:${TAG} ${DOCKER_REPO}:latest || :
46
+ # if: "${{ startsWith(github.ref, 'refs/tags/v') }}"
47
+
48
+ # - run: "docker pull ${DOCKER_REPO}:builder || :"
49
+
50
+ # - run: "docker build --pull --cache-from ${DOCKER_REPO}:builder --target builder -t ${DOCKER_REPO}:builder -f Dockerfile ."
51
+ # - run: "docker build --pull --cache-from ${DOCKER_REPO}:builder --cache-from ${DOCKER_REPO}:latest -t ${DOCKER_REPO}:${GITHUB_SHA} -f Dockerfile ."
52
+
53
+ # - run: "echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u sorah --password-stdin"
54
+ # if: "${{ github.event_name != 'pull_request' }}"
55
+
56
+ # - run: "docker push ${DOCKER_REPO}:builder"
57
+ # if: "${{ github.ref == 'refs/heads/master' }}"
58
+ # - run: "docker push ${DOCKER_REPO}:${GITHUB_SHA}"
59
+ # if: "${{ github.event_name != 'pull_request' }}"
60
+
61
+ #docker-push:
62
+ # name: docker-push
63
+ # needs: [test, integration-pebble, docker-build]
64
+ # if: "${{ github.event_name == 'push' || github.event_name == 'create' }}"
65
+ # runs-on: ubuntu-latest
66
+ # steps:
67
+ # - run: "echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u sorah --password-stdin"
68
+ # - run: "docker pull ${DOCKER_REPO}:${GITHUB_SHA}"
69
+
70
+ # - run: |
71
+ # docker tag ${DOCKER_REPO}:${GITHUB_SHA} ${DOCKER_REPO}:latest
72
+ # docker push ${DOCKER_REPO}:latest
73
+ # if: "${{ github.ref == 'refs/heads/master' }}"
74
+ # - run: |
75
+ # TAG=$(basename "${{ github.ref }}")
76
+ # docker tag ${DOCKER_REPO}:${GITHUB_SHA} ${DOCKER_REPO}:${TAG}
77
+ # docker push ${DOCKER_REPO}:${TAG}
78
+ # if: "${{ startsWith(github.ref, 'refs/tags/v') }}"
data/Dockerfile CHANGED
@@ -12,6 +12,7 @@ RUN cd /tmp && bundle install -j4 --path vendor/bundle --without 'development te
12
12
  WORKDIR /app
13
13
  ADD . /app
14
14
  RUN cp -a /tmp/.bundle /tmp/vendor /app/
15
+ RUN rm -f /app/.ruby-version
15
16
 
16
17
  EXPOSE 8080
17
18
  ENV RACK_ENV=production
data/Gemfile CHANGED
@@ -4,4 +4,5 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'omniauth-github'
7
- gem 'omniauth-google-oauth2'
7
+ gem 'omniauth-google-oauth2', '>= 0.3.1'
8
+ gem 'unicorn'
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # NginxOmniauthAdapter - Use omniauth for nginx `auth_request`
2
2
 
3
+ [![ci](https://github.com/sorah/nginx_omniauth_adapter/actions/workflows/ci.yml/badge.svg)](https://github.com/sorah/nginx_omniauth_adapter/actions/workflows/ci.yml)
4
+
3
5
  Use [omniauth](https://github.com/intridea/omniauth) for your nginx's authentication via ngx_http_auth_request_module.
4
6
 
5
7
  NginxOmniauthAdapter provides small Rack app (built with Sinatra) for `auth_request`.
@@ -17,7 +19,7 @@ $ cd example/
17
19
  $ foreman start
18
20
  ```
19
21
 
20
- http://ngx-auth-test.127.0.0.1.xip.io:18080/
22
+ http://ngx-auth-test.lo.nkmiusercontent.com:18080/
21
23
 
22
24
  (make sure to have nginx on your PATH)
23
25
 
@@ -40,13 +42,19 @@ Then write `config.ru` then deploy it. (see ./config.ru for example)
40
42
 
41
43
  ### Using docker
42
44
 
43
- TBD
45
+ - Prebuilt: https://quay.io/repository/sorah/nginx_omniauth_adapter
46
+ - Own your risk.
47
+ - They're built at circleci
48
+ - Build manually: checkout this repo and run `docker build .`.
49
+ - Much safer.
50
+ - But if you can't trust upstream image `quay.io/sorah/rbenv:2.2`, write your own Dockerfile. This is just a simple Rack app.
44
51
 
45
52
  ## Configuration
46
53
 
47
54
  environment variable is available only on included config.ru (or Docker image).
48
55
 
49
56
  - `:providers`: omniauth provider names.
57
+ - `:provider_http_header` `$NGX_OMNIAUTH_PROVIDER_HTTP_HEADER` (string): Name of HTTP header to specify OmniAuth provider to be used (see below). Defaults to 'x-ngx-omniauth-provider`.
50
58
  - `:secret` `$NGX_OMNIAUTH_SESSION_SECRET`: Rack session secret. Should be set when not on dev mode
51
59
  - `:host` `$NGX_OMNIAUTH_HOST`: URL of adapter. This is used for redirection. Should include protocol (e.g. `http://example.com`.)
52
60
  - If this is not specified, adapter will perform redirect using given `Host` header.
@@ -55,6 +63,11 @@ environment variable is available only on included config.ru (or Docker image).
55
63
  - `:app_refresh_interval` `NGX_OMNIAUTH_APP_REFRESH_INTERVAL` (integer): Interval to require refresh session cookie on app domain (in second, default 1 day).
56
64
  - `:adapter_refresh_interval` `NGX_OMNIAUTH_ADAPTER_REFRESH_INTERVAL` (integer): Interval to require re-logging in on adapter domain (in second, default 3 days).
57
65
 
66
+ ### Working with multiple OmniAuth providers
67
+
68
+ When multiple providers are passed to `:providers`, nginx_omniauth_adapter defaults to the first one in list.
69
+ Other providers in list will only be activated for requests with `x-ngx-omniauth-provider` header (key is configurable via `:provider_http_header`).
70
+
58
71
  ### Included config.ru (or Docker)
59
72
 
60
73
  You can set configuration via environment variables.
@@ -94,6 +107,8 @@ run NginxOmniauthAdapter.app(
94
107
 
95
108
  ## How it works
96
109
 
110
+ ![](http://img.sorah.jp/2015-10-08_22.55_2s4hy.png)
111
+
97
112
  1. _browser_ access to restricted area (where `auth_request` has enabled)
98
113
  2. _nginx_ sends subrequest to `/_auth/challenge`. It will be proxied to _adapter app_ (`GET /test`)
99
114
  3. _adapter app_ `/test` returns 401 when _request (browser)_ doesn't have valid cookie
data/config.ru CHANGED
@@ -74,6 +74,7 @@ end
74
74
 
75
75
  run NginxOmniauthAdapter.app(
76
76
  providers: providers,
77
+ provider_http_header: ENV['NGX_OMNIAUTH_PROVIDER_HTTP_HEADER'] || 'x-ngx-omniauth-provider',
77
78
  secret: ENV['NGX_OMNIAUTH_SECRET'],
78
79
  host: ENV['NGX_OMNIAUTH_HOST'],
79
80
  allowed_app_callback_url: allowed_app_callback_url,
data/example/Procfile CHANGED
@@ -1,3 +1,3 @@
1
1
  nginx: nginx -c `pwd`/nginx.conf
2
- adapter: bundle exec env RACK_ENV=development NGX_OMNIAUTH_HOST=http://ngx-auth.127.0.0.1.xip.io:18080 rackup -p 18081 -o 127.0.0.1 ../config.ru
2
+ adapter: bundle exec env RACK_ENV=development NGX_OMNIAUTH_HOST=http://ngx-auth.lo.nkmiusercontent.com:18080 rackup -p 18081 -o 127.0.0.1 ../config.ru
3
3
  app: bundle exec ruby test_backend.rb -p 18082 -o 127.0.0.1
@@ -6,7 +6,7 @@ upstream auth_adapter {
6
6
  }
7
7
  server {
8
8
  listen 127.0.0.1:18080;
9
- server_name ngx-auth.127.0.0.1.xip.io;
9
+ server_name ngx-auth.lo.nkmiusercontent.com;
10
10
 
11
11
  location / {
12
12
  proxy_pass http://auth_adapter;
@@ -20,12 +20,13 @@ upstream app {
20
20
  }
21
21
  server {
22
22
  listen 127.0.0.1:18080;
23
- server_name ngx-auth-test.127.0.0.1.xip.io;
23
+ server_name ngx-auth-test.lo.nkmiusercontent.com;
24
24
 
25
25
  # Restricted area
26
26
  location / {
27
27
  auth_request /_auth/challenge;
28
28
  # Trick - do internal redirection when auth_request says "need auth".
29
+ proxy_intercept_errors off;
29
30
  error_page 401 = /_auth/initiate;
30
31
 
31
32
  # Receive user info from adapter
data/example/nginx.conf CHANGED
@@ -1,6 +1,7 @@
1
1
  # vim: ft=nginx
2
2
  worker_processes 1;
3
3
  daemon off;
4
+ pid /tmp/nginx_omniauth_adapter-nginx.pid;
4
5
 
5
6
  error_log stderr;
6
7
 
@@ -13,5 +14,7 @@ http {
13
14
 
14
15
  server_names_hash_bucket_size 128;
15
16
 
17
+ access_log off;
18
+
16
19
  include nginx-site.conf;
17
20
  }
@@ -7,7 +7,7 @@ get '/' do
7
7
  {
8
8
  provider: request.env['HTTP_X_NGX_OMNIAUTH_PROVIDER'],
9
9
  user: request.env['HTTP_X_NGX_OMNIAUTH_USER'],
10
- info: JSON.parse(request.env['HTTP_X_NGX_OMNIAUTH_INFO'].unpack('m*')[0]),
10
+ info: JSON.parse(request.env['HTTP_X_NGX_OMNIAUTH_INFO'].unpack('m0')[0]),
11
11
  }.to_json
12
12
  end
13
13
 
@@ -3,6 +3,7 @@ require 'uri'
3
3
  require 'time'
4
4
  require 'openssl'
5
5
  require 'json'
6
+ require 'securerandom'
6
7
 
7
8
  module NginxOmniauthAdapter
8
9
  class App < Sinatra::Base
@@ -44,6 +45,10 @@ module NginxOmniauthAdapter
44
45
  adapter_config[:providers]
45
46
  end
46
47
 
48
+ def provider_http_header
49
+ adapter_config[:provider_http_header] || 'x-ngx-omniauth-provider'
50
+ end
51
+
47
52
  def allowed_back_to_url
48
53
  adapter_config[:allowed_back_to_url] || /./
49
54
  end
@@ -60,13 +65,30 @@ module NginxOmniauthAdapter
60
65
  adapter_config[:policy_proc] || proc { true }
61
66
  end
62
67
 
68
+ def log(h={})
69
+ h = {
70
+ time: Time.now.xmlschema,
71
+ severity: :info,
72
+ logged_in: (!!current_user).inspect,
73
+ provider: current_user && current_user[:provider],
74
+ uid: current_user && current_user[:uid],
75
+ flow_id: current_flow_id,
76
+ }.merge(h)
77
+
78
+ str = h.map { |*kv| kv.join(?:) }.join(?\t)
79
+
80
+ puts str
81
+ if h[:severity] == :warning || h[:severity] == :error
82
+ $stderr.puts str
83
+ end
84
+ end
85
+
63
86
  def default_back_to
64
87
  # TODO:
65
88
  '/'
66
89
  end
67
90
 
68
91
  def sanitized_back_to_param
69
- p params[:back_to]
70
92
  if allowed_back_to_url === params[:back_to]
71
93
  params[:back_to]
72
94
  else
@@ -75,7 +97,6 @@ module NginxOmniauthAdapter
75
97
  end
76
98
 
77
99
  def sanitized_app_callback_param
78
- p params[:callback]
79
100
  if allowed_app_callback_url === params[:callback]
80
101
  params[:callback]
81
102
  else
@@ -83,6 +104,14 @@ module NginxOmniauthAdapter
83
104
  end
84
105
  end
85
106
 
107
+ def set_flow_id!
108
+ session[:flow_id] = SecureRandom.uuid
109
+ end
110
+
111
+ def current_flow_id
112
+ session[:flow_id]
113
+ end
114
+
86
115
  def current_user
87
116
  session[:user]
88
117
  end
@@ -117,6 +146,7 @@ module NginxOmniauthAdapter
117
146
 
118
147
  def update_session!(auth = nil)
119
148
  unless session[:app_callback]
149
+ log severity: :error, message: 'missing app_callback'
120
150
  raise '[BUG] app_callback is missing'
121
151
  end
122
152
 
@@ -148,7 +178,12 @@ module NginxOmniauthAdapter
148
178
  session.merge!(adapter_session)
149
179
 
150
180
  session_param = encrypt_session_param(app_session)
181
+
182
+ log(message: 'update_session', app_callback: session[:app_callback])
183
+
151
184
  redirect "#{session.delete(:app_callback)}?session=#{session_param}"
185
+ ensure
186
+ session[:flow_id] = nil
152
187
  end
153
188
 
154
189
  def secret_key
@@ -212,10 +247,12 @@ module NginxOmniauthAdapter
212
247
 
213
248
  get '/test' do
214
249
  unless current_user
250
+ log(message: 'test_not_logged_in', original_uri: request.env['HTTP_X_NGX_OMNIAUTH_ORIGINAL_URI'])
215
251
  halt 401
216
252
  end
217
253
 
218
254
  if app_authorization_expired?
255
+ log(message: 'test_app_authorization_expired', original_uri: request.env['HTTP_X_NGX_OMNIAUTH_ORIGINAL_URI'])
219
256
  halt 401
220
257
  end
221
258
 
@@ -226,7 +263,7 @@ module NginxOmniauthAdapter
226
263
  headers(
227
264
  'x-ngx-omniauth-provider' => current_user[:provider],
228
265
  'x-ngx-omniauth-user' => current_user[:uid],
229
- 'x-ngx-omniauth-info' => [current_user[:info].to_json].pack('m*'),
266
+ 'x-ngx-omniauth-info' => [current_user[:info].to_json].pack('m0'),
230
267
  )
231
268
 
232
269
  content_type :text
@@ -238,34 +275,58 @@ module NginxOmniauthAdapter
238
275
  callback = URI.encode_www_form_component(request.env['HTTP_X_NGX_OMNIAUTH_INITIATE_CALLBACK'])
239
276
 
240
277
  if back_to == '' || callback == '' || back_to.nil? || callback.nil?
278
+ log(severity: :error, message: 'initiate_no_required_params', back_to: back_to, callback: callback)
241
279
  halt 400, {'Content-Type' => 'text/plain'}, 'x-ngx-omniauth-initiate-back-to and x-ngx-omniauth-initiate-callback header are required'
242
280
  end
243
281
 
282
+ log(message: 'initiate', adapter_host: adapter_host, back_to: back_to, callback: callback)
283
+
244
284
  redirect "#{adapter_host}/auth?back_to=#{back_to}&callback=#{callback}"
245
285
  end
246
286
 
247
287
  get '/auth' do
248
- # TODO: choose provider
288
+ set_flow_id!
289
+
290
+ provider_requested = request.env["HTTP_#{provider_http_header.gsub('-', '_').upcase}"]
291
+ if provider_requested
292
+ if providers.include?(provider_requested.to_sym)
293
+ provider = provider_requested.to_sym
294
+ else
295
+ halt 401, {'Content-Type' => 'text/plain'}, 'requested provider not available'
296
+ end
297
+ else
298
+ # default to the first provider in list
299
+ provider = providers[0]
300
+ end
301
+
249
302
  session[:back_to] = sanitized_back_to_param
250
303
  session[:app_callback] = sanitized_app_callback_param
251
- p [:auth, session]
304
+
305
+ if session[:back_to] == '' || session[:app_callback] == '' || session[:back_to].nil? || session[:app_callback].nil?
306
+ log(severity: :error, message: 'auth_invalid_params', back_to: params[:back_to], callback: params[:callback])
307
+ halt 400, {'Content-Type' => 'text/plain'}, 'back_to or/and app_callback is invalid'
308
+ end
252
309
 
253
310
  if current_user && !adapter_authorization_expired?
254
- p [:auth, :update]
311
+ log(message: 'auth_refresh_app', back_to: params[:back_to], callback: params[:callback])
255
312
  update_session!
256
313
  else
257
- p [:auth, :redirect]
258
- redirect "#{adapter_host}/auth/#{providers[0]}"
314
+ log(message: 'auth', provider: provider, back_to: params[:back_to], callback: params[:callback])
315
+ redirect "#{adapter_host}/auth/#{provider}"
259
316
  end
260
317
  end
261
318
 
262
319
  omniauth_callback = proc do
320
+
263
321
  session[:user_data] = {}
264
322
 
265
323
  unless instance_eval(&on_login_proc)
324
+ log(severity: :warning, message: 'omniauth_callback_forbidden', new_uid: env['omniauth.auth'][:uid])
266
325
  halt 403, {'Content-Type' => 'text/plain'}, 'Forbidden (on_login_proc policy)'
267
326
  end
268
327
 
328
+ log(message: 'omniauth_callback', new_uid: env['omniauth.auth'][:uid])
329
+
269
330
  session[:logged_in_at] = Time.now.xmlschema
270
331
  update_session! env['omniauth.auth']
271
332
  end
@@ -275,6 +336,7 @@ module NginxOmniauthAdapter
275
336
  get '/callback' do # app side
276
337
  app_session = decrypt_session_param(params[:session])
277
338
  session.merge!(app_session)
339
+ log(message: 'app_callback', back_to: session[:back_to])
278
340
  redirect session.delete(:back_to)
279
341
  end
280
342
  end
@@ -1,3 +1,3 @@
1
1
  module NginxOmniauthAdapter
2
- VERSION = "0.2.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "sinatra"
22
- spec.add_dependency "omniauth"
22
+ spec.add_dependency "omniauth", '< 2'
23
23
 
24
24
  spec.add_development_dependency "bundler"
25
25
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nginx_omniauth_adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shota Fukumori (sora_h)
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-02 00:00:00.000000000 Z
11
+ date: 2022-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: omniauth
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "<"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -108,13 +108,14 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
- description:
111
+ description:
112
112
  email:
113
113
  - her@sorah.jp
114
114
  executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
+ - ".github/workflows/ci.yml"
118
119
  - ".gitignore"
119
120
  - ".rspec"
120
121
  - ".travis.yml"
@@ -138,7 +139,7 @@ homepage: https://github.com/sorah/nginx_omniauth_adapter
138
139
  licenses:
139
140
  - MIT
140
141
  metadata: {}
141
- post_install_message:
142
+ post_install_message:
142
143
  rdoc_options: []
143
144
  require_paths:
144
145
  - lib
@@ -153,9 +154,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
154
  - !ruby/object:Gem::Version
154
155
  version: '0'
155
156
  requirements: []
156
- rubyforge_project:
157
- rubygems_version: 2.5.0
158
- signing_key:
157
+ rubygems_version: 3.4.0.dev
158
+ signing_key:
159
159
  specification_version: 4
160
160
  summary: omniauth adapter for ngx_http_auth_request_module
161
161
  test_files: []