Class: Rack::WWWhisper
- Inherits:
-
Object
- Object
- Rack::WWWhisper
- Defined in:
- lib/rack/wwwhisper.rb
Overview
Communicates with the wwwhisper service to authorize each incoming request. Acts as a proxy for requests to locations handled by wwwhisper (/wwwhisper/auth and /wwwhisper/admin)
For each incoming request an authorization query is sent. The query contains a normalized path that a request is trying to access and wwwhisper session cookies. The query result determines the action to be performed:
- 200
-
request is allowed and passed down the Rack stack.
- 401
-
the user is not authenticated, request is denied, login page is returned.
- 403
-
the user is not authorized, request is denied, error is returned.
- any other
-
error while communicating with wwwhisper, request is denied.
This class is thread safe, it can handle multiple simultaneous requests.
Defined Under Namespace
Classes: NoPublicCache
Constant Summary collapse
- @@WWWHISPER_PREFIX =
Path prefix of requests that are passed to wwwhisper.
'/wwwhisper/'
- @@AUTH_COOKIES_PREFIX =
Name prefix of cookies that are passed to wwwhisper.
'wwwhisper'
- @@FORWARDED_HEADERS =
Headers that are passed to wwwhisper (‘Cookie’ is handled in a special way: only wwwhisper related cookies are passed).
In addition, the current site URL is passed in the Site-Url header. This is needed to disallow access with access tokens generated for other sites and to construct Location headers in redirects.
wwwhisper library version is passed in the User-Agent header. This is to warn the site owner if a vulnerability in the library is discovered and the library needs to be updated.
['Accept', 'Accept-Language', 'Cookie', 'Origin', 'X-CSRFToken', 'X-Requested-With']
- @@DEFAULT_IFRAME =
%Q[<script type="text/javascript" src="%s"> </script> ]
Instance Method Summary collapse
-
#auth_query(queried_path) ⇒ Object
Exposed for tests.
- #call(env) ⇒ Object
-
#initialize(app) ⇒ WWWhisper
constructor
Following environment variables are recognized: 1.
-
#wwwhisper_path(suffix) ⇒ Object
Exposed for tests.
Constructor Details
#initialize(app) ⇒ WWWhisper
Following environment variables are recognized:
-
WWWHISPER_DISABLE: useful for a local development environment.
-
WWWHISPER_URL: an address of a wwwhisper service that must be set if WWWHISPER_DISABLE is not set. The url includes credentials that identify a protected site. If the same credentials are used for www.example.org and www.example.com, the sites are treated as one: access control rules defined for one site, apply to the other site.
-
WWWHISPER_IFRAME: an HTML snippet to be injected into returned HTML documents (has a default value).
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/rack/wwwhisper.rb', line 63 def initialize(app) @app = app if not ENV['WWWHISPER_URL'] def self.call(env) # Delay check for WWWHISPER_DISABLE until the first # request. This way Rails assets pipeline does not fail if # environment variables are not set (as is the case on # Heroku). if ENV['WWWHISPER_DISABLE'] != '1' raise(StandardError, 'WWWHISPER_URL nor WWWHISPER_DISABLE environment variable set') end @app.call(env) end return end @app = NoPublicCache.new(app) # net/http/persistent connections are thread safe. @http = http_init() @wwwhisper_uri = parse_uri(ENV['WWWHISPER_URL']) @wwwhisper_iframe = ENV['WWWHISPER_IFRAME'] || sprintf(@@DEFAULT_IFRAME, wwwhisper_path('auth/iframe.js')) @wwwhisper_iframe_bytesize = @wwwhisper_iframe.bytesize end |
Instance Method Details
#auth_query(queried_path) ⇒ Object
Exposed for tests.
97 98 99 |
# File 'lib/rack/wwwhisper.rb', line 97 def auth_query(queried_path) wwwhisper_path "auth/api/is-authorized/?path=#{queried_path}" end |
#call(env) ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/rack/wwwhisper.rb', line 101 def call(env) req = Request.new(env) normalize_path(req) # Requests to /@@WWWHISPER_PREFIX/auth/ should not be authorized, # every visitor can access login pages. return dispatch(req) if req.path =~ %r{^#{wwwhisper_path('auth')}} debug req, "sending auth request for #{req.path}" auth_resp = auth_request(req) if auth_resp.code == '200' debug req, 'access granted' user = auth_resp['User'] env['REMOTE_USER'] = user if user status, headers, body = dispatch(req) if should_inject_iframe(status, headers) body = inject_iframe(headers, body) end headers['User'] = user if user [status, headers, body] else debug req, { '401' => 'user not authenticated', '403' => 'access_denied', }[auth_resp.code] || 'auth request failed' sub_response_to_rack(req, auth_resp) end end |
#wwwhisper_path(suffix) ⇒ Object
Exposed for tests.
92 93 94 |
# File 'lib/rack/wwwhisper.rb', line 92 def wwwhisper_path(suffix) "#{@@WWWHISPER_PREFIX}#{suffix}" end |