brupm
brupm

Reputation: 1183

Trigger basic HTTP auth from within middleware

I have created a custom middleware for rails which will intercept all requests and make sure it's coming from an authorized IP, otherwise it should prompt for a basic http auth user/name password.

This is currently what it looks like:

require 'net/http'

class AuthorizeEnvironment
  def initialize(app)
    @app = app
  end

  def call(env)
    if AppConstants.approved_doximity_ips.include?(env["REMOTE_ADDR"])
      @app.call(env)
    elsif authorized?(env)
      @app.call(env)
    else
      [403, {"Content-Type" => "text/html"}, ["Not Authorized on this environment."]]
    end
  end

  def authorized?(env)
    @auth ||= Rack::Auth::Basic::Request.new(env)
    @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ['username', 'password']
  end
end

The issue with this code is that I can't seem to find a way to trigger the http auth window on the browser. I reviewed this and didn't see any obvious indication of how this is done.

Could you please point me in the right direction?

Upvotes: 1

Views: 2225

Answers (3)

Eric Boehs
Eric Boehs

Reputation: 1327

You need to provide a WWW-Authenticate header. See.

I assume, in your else, you would do:

[401, {'WWW-Authenticate' => 'Basic realm="Application"', "Content-Type" => "text/html"}, ["Not Authorized on this environment."]]

Upvotes: 1

Lasse Skindstad Ebert
Lasse Skindstad Ebert

Reputation: 3390

I'm using Rack::Auth::Basic directly and saves myself the validation part:

class BasicAuth
  def initialize(app)
    @app = app
  end

  def call(env)
    if env["PATH_INFO"] == '/supersecret' # Any condition here
      auth = Rack::Auth::Basic.new(@app) do |u, p|
        u == username && p == password
      end
      auth.call env
    else
      @app.call env
    end
  end

  def username
    ENV["username"]
  end

  def password
    ENV["password"]
  end
end

```

Upvotes: 6

Walton Hoops
Walton Hoops

Reputation: 864

I haven't tested your code, but it looks like your replying with a 403 which means "forbidden". I.e., the currently logged in user does not have permissions to access this resource.

From the RFC (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)

The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.

Instead, you need to use a 401, and only reply with a 403 ONLY if the currently logged in user cannot access the resource.

Upvotes: 1

Related Questions