Commit 836653f8 authored by Sean Arnold's avatar Sean Arnold Committed by Igor Drozdov

Add HTTP Basic support for Alert authentication

parent 5e8f3a30
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
module Projects module Projects
module Alerting module Alerting
class NotificationsController < Projects::ApplicationController class NotificationsController < Projects::ApplicationController
include ActionController::HttpAuthentication::Basic
respond_to :json respond_to :json
skip_before_action :verify_authenticity_token skip_before_action :verify_authenticity_token
...@@ -27,9 +29,19 @@ module Projects ...@@ -27,9 +29,19 @@ module Projects
end end
def extract_alert_manager_token(request) def extract_alert_manager_token(request)
extract_bearer_token(request) || extract_basic_auth_token(request)
end
def extract_bearer_token(request)
Doorkeeper::OAuth::Token.from_bearer_authorization(request) Doorkeeper::OAuth::Token.from_bearer_authorization(request)
end end
def extract_basic_auth_token(request)
_username, token = user_name_and_password(request)
token
end
def notify_service def notify_service
notify_service_class.new(project, notification_payload) notify_service_class.new(project, notification_payload)
end end
......
...@@ -125,17 +125,7 @@ NOTE: ...@@ -125,17 +125,7 @@ NOTE:
Ensure your requests are smaller than the Ensure your requests are smaller than the
[payload application limits](../../administration/instance_limits.md#generic-alert-json-payloads). [payload application limits](../../administration/instance_limits.md#generic-alert-json-payloads).
Example request: ### Example request body
```shell
curl --request POST \
--data '{"title": "Incident title"}' \
--header "Authorization: Bearer <authorization_key>" \
--header "Content-Type: application/json" \
<url>
```
The `<authorization_key>` and `<url>` values can be found when configuring an alert integration.
Example payload: Example payload:
...@@ -157,6 +147,55 @@ Example payload: ...@@ -157,6 +147,55 @@ Example payload:
} }
``` ```
## Authorization
The following authorization methods are accepted:
- Bearer authorization header
- Basic authentication
The `<authorization_key>` and `<url>` values can be found when configuring an alert integration.
### Bearer authorization header
The authorization key can be used as the Bearer token:
```shell
curl --request POST \
--data '{"title": "Incident title"}' \
--header "Authorization: Bearer <authorization_key>" \
--header "Content-Type: application/json" \
<url>
```
### Basic authentication
The authorization key can be used as the `password`. The `username` is left blank:
- username: <blank>
- pasword: authorization_key
```shell
curl --request POST \
--data '{"title": "Incident title"}' \
--header "Authorization: Basic <base_64_encoded_credentials>" \
--header "Content-Type: application/json" \
<url>
```
Basic authentication can also be used with credentials directly in the URL:
```shell
curl --request POST \
--data '{"title": "Incident title"}' \
--header "Content-Type: application/json" \
<username:password@url>
```
WARNING:
Using your authorization key in the URL is insecure, as it's visible in server logs. We recommend
using one of the above header options if your tooling supports it.
## Triggering test alerts ## Triggering test alerts
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab in 13.2. > [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab in 13.2.
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Projects::Alerting::NotificationsController do RSpec.describe Projects::Alerting::NotificationsController do
include HttpBasicAuthHelpers
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:environment) { create(:environment, project: project) } let_it_be(:environment) { create(:environment, project: project) }
...@@ -53,86 +55,96 @@ RSpec.describe Projects::Alerting::NotificationsController do ...@@ -53,86 +55,96 @@ RSpec.describe Projects::Alerting::NotificationsController do
end end
end end
context 'bearer token' do shared_examples 'a working token' do
context 'when set' do it 'extracts token' do
context 'when extractable' do expect(notify_service).to receive(:execute).with('some token', nil)
before do
request.headers['HTTP_AUTHORIZATION'] = 'Bearer some token'
end
it 'extracts bearer token' do
expect(notify_service).to receive(:execute).with('some token', nil)
make_request
end
context 'with a corresponding integration' do
context 'with integration parameters specified' do
let_it_be_with_reload(:integration) { create(:alert_management_http_integration, project: project) }
let(:params) { project_params(endpoint_identifier: integration.endpoint_identifier, name: integration.name) } make_request
end
context 'the integration is active' do
it 'extracts and finds the integration' do
expect(notify_service).to receive(:execute).with('some token', integration)
make_request context 'with a corresponding integration' do
end context 'with integration parameters specified' do
end let_it_be_with_reload(:integration) { create(:alert_management_http_integration, project: project) }
context 'when the integration is inactive' do let(:params) { project_params(endpoint_identifier: integration.endpoint_identifier, name: integration.name) }
before do
integration.update!(active: false)
end
it 'does not find an integration' do context 'the integration is active' do
expect(notify_service).to receive(:execute).with('some token', nil) it 'extracts and finds the integration' do
expect(notify_service).to receive(:execute).with('some token', integration)
make_request make_request
end
end
end end
end
context 'without integration parameters specified' do context 'when the integration is inactive' do
let_it_be(:integration) { create(:alert_management_http_integration, :legacy, project: project) } before do
integration.update!(active: false)
end
it 'extracts and finds the legacy integration' do it 'does not find an integration' do
expect(notify_service).to receive(:execute).with('some token', integration) expect(notify_service).to receive(:execute).with('some token', nil)
make_request make_request
end
end end
end end
end end
context 'when inextractable' do context 'without integration parameters specified' do
it 'passes nil for a non-bearer token' do let_it_be(:integration) { create(:alert_management_http_integration, :legacy, project: project) }
request.headers['HTTP_AUTHORIZATION'] = 'some token'
expect(notify_service).to receive(:execute).with(nil, nil) it 'extracts and finds the legacy integration' do
expect(notify_service).to receive(:execute).with('some token', integration)
make_request make_request
end end
end end
end end
end
context 'when missing' do context 'with bearer token' do
it 'passes nil' do context 'when set' do
expect(notify_service).to receive(:execute).with(nil, nil) before do
request.headers.merge(build_token_auth_header('some token'))
make_request
end end
it_behaves_like 'a working token'
end
end
context 'with basic auth token' do
before do
request.headers.merge basic_auth_header(nil, 'some token')
end
it_behaves_like 'a working token'
end
context 'when inextractable token' do
it 'passes nil for a non-bearer token' do
request.headers['HTTP_AUTHORIZATION'] = 'some token'
expect(notify_service).to receive(:execute).with(nil, nil)
make_request
end
end
context 'when missing token' do
it 'passes nil' do
expect(notify_service).to receive(:execute).with(nil, nil)
make_request
end end
end end
end end
context 'generic alert payload' do context 'with generic alert payload' do
it_behaves_like 'process alert payload', Projects::Alerting::NotifyService do it_behaves_like 'process alert payload', Projects::Alerting::NotifyService do
let(:payload) { { title: 'Alert title' } } let(:payload) { { title: 'Alert title' } }
end end
end end
context 'Prometheus alert payload' do context 'with Prometheus alert payload' do
include PrometheusHelpers include PrometheusHelpers
it_behaves_like 'process alert payload', Projects::Prometheus::Alerts::NotifyService do it_behaves_like 'process alert payload', Projects::Prometheus::Alerts::NotifyService do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment