Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds HTTP basic authentication #4

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ If you are using Sprockets, add the ActiveInsights css file to manifest.js:
//= link active_insights/application.css
```

To use HTTP basic authentication, enable it and define a user and password:

```ruby
config.active_insights.http_basic_auth_enabled = true
config.active_insights.http_basic_auth_user = ENV["BASIC_AUTH_USER"]
config.active_insights.http_basic_auth_password = ENV["BASIC_AUTH_PASSWORD"]
```

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/active_insights/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module ActiveInsights
class ApplicationController < ActionController::Base
include ActiveInsights::BasicAuthentication

protect_from_forgery with: :exception

around_action :setup_time_zone
Expand Down
34 changes: 34 additions & 0 deletions app/controllers/concerns/active_insights/basic_authentication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

module ActiveInsights::BasicAuthentication
extend ActiveSupport::Concern

included do
before_action :authenticate_by_http_basic
end

def authenticate_by_http_basic
return unless http_basic_authentication_enabled?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this extra check? If the creds are set i think we are safe to assume auth is enabled.

Copy link
Author

@cannikin cannikin Dec 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what MissionControl is doing, not sure what the benefit is...maybe with ENV vars always being strings you could accidentally set user/pass to an empty string/nil? So having to also set enabled makes it explicit that you really do want to turn it on...


if http_basic_authentication_configured?
http_basic_authenticate_or_request_with(**http_basic_auth_credentials)
else
head :unauthorized
end
end

def http_basic_authentication_enabled?
ActiveInsights.http_basic_auth_enabled
end

def http_basic_authentication_configured?
http_basic_auth_credentials.values.all?(&:present?)
end

def http_basic_auth_credentials
{
name: ActiveInsights.http_basic_auth_user,
password: ActiveInsights.http_basic_auth_password
}.transform_values(&:presence)
end
end
4 changes: 3 additions & 1 deletion lib/active_insights.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
require "active_insights/engine"

module ActiveInsights
mattr_accessor :connects_to, :ignored_endpoints, :enabled
mattr_accessor :connects_to, :ignored_endpoints, :enabled,
:http_basic_auth_enabled, :http_basic_auth_user,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think about moving this into a new object? For example:

config.active_insights.http_basic_auth.enabled = true

Then we can remove a bunch of the controller stuff and move it into its own class:

class ActiveInsights::HttpBasicAuth
  attr_accessor :enabled, :user, :password 

  def enabled?
    enabled
  end

  ..
end

module ActiveInsights
  def self.http_basic_auth
    @http_basic_auth ||= HttpBasicAuth.new
  end
end

:http_basic_auth_password

class << self
def ignored_endpoint?(payload)
Expand Down
2 changes: 1 addition & 1 deletion lib/active_insights/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module ActiveInsights
VERSION = "1.3.1"
VERSION = "1.4.0"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be reverted

end
28 changes: 28 additions & 0 deletions test/active_insights_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,35 @@
require "test_helper"

class ActiveInsightsTest < ActiveSupport::TestCase
teardown do
ActiveInsights.http_basic_auth_enabled = nil
ActiveInsights.http_basic_auth_user = nil
ActiveInsights.http_basic_auth_password = nil
end

test "it has a version number" do
assert ActiveInsights::VERSION
end

test "it does not enabled http basic auth by default" do
assert_not ActiveInsights.http_basic_auth_enabled
end

test "it has an accessor to set whether http basic auth is enabled" do
ActiveInsights.http_basic_auth_enabled = true

assert ActiveInsights.http_basic_auth_enabled
end

test "it has an accessor to set http basic auth user" do
ActiveInsights.http_basic_auth_user = "johndoe"

assert_equal "johndoe", ActiveInsights.http_basic_auth_user
end

test "it has an accessor to set http basic auth password" do
ActiveInsights.http_basic_auth_password = "secret"

assert_equal "secret", ActiveInsights.http_basic_auth_password
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# frozen_string_literal: true

require "test_helper"

class ActiveInsights::BasicAuthenticationTest < ActionDispatch::IntegrationTest
test "it does not require http basic auth by default" do
get active_insights.requests_path

assert_response :success
end

test "it requires http basic auth when enabled" do
with_http_basic_auth do
get active_insights.requests_path

assert_response :unauthorized
end
end

test "allows access with correct credentials" do
with_http_basic_auth(user: "dev", password: "secret") do
get active_insights.requests_path, headers: auth_headers("dev", "secret")

assert_response :success
end
end

test "disallows access with incorrect credentials" do
with_http_basic_auth(user: "dev", password: "secret") do
get active_insights.requests_path, headers: auth_headers("dev", "wrong")

assert_response :unauthorized
end
end

private

# rubocop:disable Metrics/MethodLength
def with_http_basic_auth(enabled: true, user: nil, password: nil)
previous_enabled, ActiveInsights.http_basic_auth_enabled =
ActiveInsights.http_basic_auth_enabled, enabled
previous_user, ActiveInsights.http_basic_auth_user =
ActiveInsights.http_basic_auth_user, user
previous_password, ActiveInsights.http_basic_auth_password =
ActiveInsights.http_basic_auth_password, password
yield
ensure
ActiveInsights.http_basic_auth_enabled = previous_enabled
ActiveInsights.http_basic_auth_user = previous_user
ActiveInsights.http_basic_auth_password = previous_password
end
# rubocop:enable Metrics/MethodLength

def auth_headers(user, password)
{
Authorization:
ActionController::HttpAuthentication::Basic.encode_credentials(
user, password
)
}
end
end