Skip to content

Commit

Permalink
Merge pull request #209 from xmidt-org/feature/redesign
Browse files Browse the repository at this point in the history
initial checkin ideas
  • Loading branch information
johnabass authored Dec 1, 2023
2 parents 3a524c3 + 70771d3 commit 2a6591f
Show file tree
Hide file tree
Showing 16 changed files with 861 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .reuse/dep5
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,10 @@ Files: examples/basculehttp/go.sum
Copyright: SPDX-FileCopyrightText: 2019 Comcast Cable Communications Management, LLC
License: Apache-2.0

Files: v2/go.mod
Copyright: SPDX-FileCopyrightText: 2019 Comcast Cable Communications Management, LLC
License: Apache-2.0

Files: v2/go.sum
Copyright: SPDX-FileCopyrightText: 2019 Comcast Cable Communications Management, LLC
License: Apache-2.0
28 changes: 28 additions & 0 deletions v2/authenticator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: 2020 Comcast Cable Communications Management, LLC
// SPDX-License-Identifier: Apache-2.0

package bascule

import "go.uber.org/multierr"

// Authenticator provides a strategy for verifying that a Token
// is valid beyond just simple parsing. For example, an Authenticator may
// verify certain roles or capabilities.
type Authenticator interface {
// Authenticate verifies the given Token.
Authenticate(Token) error
}

// Authenticators is an aggregate Authenticator.
type Authenticators []Authenticator

// Authenticate applies each contained Authenticator in order. All Authenticators
// are executed. The returned error, if not nil, will be an aggregate of all errors
// that occurred.
func (as Authenticators) Authenticate(t Token) (err error) {
for _, auth := range as {
err = multierr.Append(err, auth.Authenticate(t))
}

return
}
11 changes: 11 additions & 0 deletions v2/authorizer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2020 Comcast Cable Communications Management, LLC
// SPDX-License-Identifier: Apache-2.0

package bascule

// Authorizer is a strategy for verifying that a given Token has
// access to resources.
type Authorizer interface {
// Authorize verifies that the given Token can access a resource.
Authorize(resource any, t Token) error
}
57 changes: 57 additions & 0 deletions v2/basculehttp/accessor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-FileCopyrightText: 2020 Comcast Cable Communications Management, LLC
// SPDX-License-Identifier: Apache-2.0

package basculehttp

import (
"net/http"
"strings"

"github.com/xmidt-org/bascule/v2"
)

const DefaultAuthorizationHeader = "Authorization"

// Accessor is the strategy for extracting the raw, serialized credentials
// from an HTTP request.
type Accessor interface {
// GetCredentials obtains the raw, serialized credentials from the request.
GetCredentials(*http.Request) (string, error)
}

var defaultAccessor Accessor = AuthorizationAccessor{}

func DefaultAccessor() Accessor { return defaultAccessor }

// AuthorizationAccessor is an Accessor that pulls the serialized credentials
// from an HTTP header of the format defined by https://www.rfc-editor.org/rfc/rfc7235#section-4.2.
// Only the single header is considered.
type AuthorizationAccessor struct {
// Header is the name of the Authorization header. If unset, then
// DefaultAuthorizationHeader is used.
Header string
}

func (aa AuthorizationAccessor) header() string {
if len(aa.Header) == 0 {
return DefaultAuthorizationHeader
}

return aa.Header
}

func (aa AuthorizationAccessor) GetCredentials(r *http.Request) (serialized string, err error) {
header := aa.header()
serialized = r.Header.Get(header)

if len(serialized) == 0 {
var reason strings.Builder
reason.WriteString("missing header ")
reason.WriteString(header)
err = &bascule.MissingCredentialsError{
Reason: reason.String(),
}
}

return
}
41 changes: 41 additions & 0 deletions v2/basculehttp/basicToken.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2020 Comcast Cable Communications Management, LLC
// SPDX-License-Identifier: Apache-2.0

package basculehttp

import (
"encoding/base64"
"strings"

"github.com/xmidt-org/bascule/v2"
)

type basicToken struct {
credentials bascule.Credentials
userName string
}

func (bt *basicToken) Credentials() bascule.Credentials { return bt.credentials }

func (bt *basicToken) Principal() string { return bt.userName }

type basicTokenParser struct{}

func (basicTokenParser) Parse(c bascule.Credentials) (t bascule.Token, err error) {
var decoded []byte
decoded, err = base64.StdEncoding.DecodeString(c.Value)
if err == nil {
if userName, _, ok := strings.Cut(string(decoded), ":"); ok {
t = &basicToken{
credentials: c,
userName: userName,
}
} else {
err = &bascule.InvalidCredentialsError{
Raw: c.Value,
}
}
}

return
}
119 changes: 119 additions & 0 deletions v2/basculehttp/challenge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-FileCopyrightText: 2020 Comcast Cable Communications Management, LLC
// SPDX-License-Identifier: Apache-2.0

package basculehttp

import (
"net/http"
"strings"

"github.com/xmidt-org/bascule/v2"
)

const (
BasicScheme bascule.Scheme = "Basic"
BearerScheme bascule.Scheme = "Bearer"

// WwwAuthenticateHeaderName is the HTTP header used for StatusUnauthorized challenges.
WwwAuthenticateHeaderName = "WWW-Authenticate"

// DefaultBasicRealm is the realm used for a basic challenge
// when no realm is supplied.
DefaultBasicRealm string = "bascule"

// DefaultBearerRealm is the realm used for a bearer challenge
// when no realm is supplied.
DefaultBearerRealm string = "bascule"
)

// Challenge represents a WWW-Authenticate challenge.
type Challenge interface {
// FormatAuthenticate formats the authenticate string.
FormatAuthenticate(strings.Builder)
}

// Challenges represents a sequence of challenges to associated with
// a StatusUnauthorized response.
type Challenges []Challenge

// WriteHeader inserts one WWW-Authenticate header per challenge in this set.
// If this set is empty, the given http.Header is not modified.
//
// This method returns the count of headers added, which will be zero (0) for
// an empty Challenges.
func (chs Challenges) WriteHeader(h http.Header) int {
var o strings.Builder
for _, ch := range chs {
ch.FormatAuthenticate(o)
h.Add(WwwAuthenticateHeaderName, o.String())
o.Reset()
}

return len(chs)
}

// BasicChallenge represents a WWW-Authenticate basic auth challenge.
type BasicChallenge struct {
// Scheme is the name of scheme supplied in the challenge. If this
// field is unset, BasicScheme is used.
Scheme bascule.Scheme

// Realm is the name of the realm for the challenge. If this field
// is unset, DefaultBasicRealm is used.
//
// Note that this field should always be set. The default isn't very
// useful outside of development.
Realm string

// UTF8 indicates whether "charset=UTF-8" is appended to the challenge.
// This is the only charset allowed for a Basic challenge.
UTF8 bool
}

func (bc BasicChallenge) FormatAuthenticate(o strings.Builder) {
if len(bc.Scheme) > 0 {
o.WriteString(string(bc.Scheme))
} else {
o.WriteString(string(BasicScheme))
}

o.WriteString(` realm="`)
if len(bc.Realm) > 0 {
o.WriteString(bc.Realm)
} else {
o.WriteString(DefaultBasicRealm)
}

o.WriteRune('"')
if bc.UTF8 {
o.WriteString(`, charset="UTF-8"`)
}
}

type BearerChallenge struct {
// Scheme is the name of scheme supplied in the challenge. If this
// field is unset, BearerScheme is used.
Scheme bascule.Scheme

// Realm is the name of the realm for the challenge. If this field
// is unset, DefaultBearerRealm is used.
//
// Note that this field should always be set. The default isn't very
// useful outside of development.
Realm string
}

func (bc BearerChallenge) FormatAuthenticate(o strings.Builder) {
if len(bc.Scheme) > 0 {
o.WriteString(string(bc.Scheme))
} else {
o.WriteString(string(BasicScheme))
}

o.WriteString(` realm="`)
if len(bc.Realm) > 0 {
o.WriteString(bc.Realm)
} else {
o.WriteString(DefaultBasicRealm)
}
}
Loading

0 comments on commit 2a6591f

Please sign in to comment.