Skip to content

Commit

Permalink
Improve token authentication docs and handler
Browse files Browse the repository at this point in the history
With these changes, the identity will be undefined if a token is not
specified. This is less surprising than the empty string that would be
set prior to these changes.

Fixes #901

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
  • Loading branch information
tsandall committed Sep 4, 2018
1 parent cc22d52 commit 4aa9d71
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 13 deletions.
8 changes: 7 additions & 1 deletion docs/book/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -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``.
Expand Down
13 changes: 8 additions & 5 deletions server/authorizer/authorizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions server/identifier/identifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
14 changes: 10 additions & 4 deletions server/identifier/identifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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 {
Expand All @@ -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)
}
Expand Down

0 comments on commit 4aa9d71

Please sign in to comment.