diff --git a/docs/book/security.md b/docs/book/security.md index eaa581dfac..a6d89d5b36 100644 --- a/docs/book/security.md +++ b/docs/book/security.md @@ -82,7 +82,13 @@ default to `off`. For authentication, OPA supports: -- [Bearer tokens](/rest-api.md#bearer-tokens): Bearer tokens are enabled by starting OPA with ``--authentication=token``. +- [Bearer tokens](/rest-api.md#bearer-tokens): Bearer tokens are enabled by +starting OPA with ``--authentication=token``. When the `token` authentication +mode is enabled, OPA will extract the Bearer token from incoming API requests +and provide to the authorization handler. When you use the `token` +authentication, you must configure an authorization policy that checks the +tokens. If the client does not supply a Bearer token, the `input.identity` +value will be undefined when the authorization policy is evaluated. For authorization, OPA relies on policy written in Rego. Authorization is enabled by starting OPA with ``--authorization=basic``. diff --git a/server/authorizer/authorizer.go b/server/authorizer/authorizer.go index c6e5f30765..962053acca 100644 --- a/server/authorizer/authorizer.go +++ b/server/authorizer/authorizer.go @@ -85,14 +85,17 @@ func makeInput(r *http.Request) (interface{}, error) { } method := strings.ToUpper(r.Method) - identity := identifier.Identity(r) query := r.URL.Query() input := map[string]interface{}{ - "path": path, - "method": method, - "identity": identity, - "params": query, + "path": path, + "method": method, + "params": query, + } + + identity, ok := identifier.Identity(r) + if ok { + input["identity"] = identity } return input, nil diff --git a/server/identifier/identifier.go b/server/identifier/identifier.go index b7a6b4653c..6de3ad0d3a 100644 --- a/server/identifier/identifier.go +++ b/server/identifier/identifier.go @@ -12,13 +12,13 @@ import ( ) // Identity returns the identity of the caller associated with ctx. -func Identity(r *http.Request) string { +func Identity(r *http.Request) (string, bool) { ctx := r.Context() v, ok := ctx.Value(identity).(string) if ok { - return v + return v, true } - return "" + return "", false } // SetIdentity returns a new http.Request with the identity set to v. diff --git a/server/identifier/identifier_test.go b/server/identifier/identifier_test.go index c78cf80add..1c5b8bbed5 100644 --- a/server/identifier/identifier_test.go +++ b/server/identifier/identifier_test.go @@ -11,10 +11,11 @@ import ( type mockHandler struct { identity string + defined bool } func (h *mockHandler) ServeHTTP(_ http.ResponseWriter, r *http.Request) { - h.identity = Identity(r) + h.identity, h.defined = Identity(r) } func TestTokenBased(t *testing.T) { @@ -30,10 +31,11 @@ func TestTokenBased(t *testing.T) { tests := []struct { value string expected string + defined bool }{ - {"", ""}, - {"Bearer this-is-the-token", "this-is-the-token"}, - {"Bearer this-is-the-token-with-spaces", "this-is-the-token-with-spaces"}, + {"", "", false}, + {"Bearer this-is-the-token", "this-is-the-token", true}, + {"Bearer this-is-the-token-with-spaces", "this-is-the-token-with-spaces", true}, } for _, tc := range tests { @@ -44,6 +46,10 @@ func TestTokenBased(t *testing.T) { handler.ServeHTTP(nil, req) + if mock.defined != tc.defined { + t.Fatalf("Expected defined to be %v but got: %v", tc.defined, mock.defined) + } + if mock.identity != tc.expected { t.Fatalf("Expected identity to be %s but got: %s", tc.expected, mock.identity) }