Skip to content

Commit

Permalink
Generic auth improvements (#257)
Browse files Browse the repository at this point in the history
* Add capability to use user-provided ExtractAuthenticationToken on generic auth scheme
* adding support for returning 5XX status code for generic auth flow
  • Loading branch information
joelsdc authored and jeevatkm committed Sep 22, 2019
1 parent def102f commit 0bcfe2c
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 9 deletions.
18 changes: 16 additions & 2 deletions security.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"strings"

"aahframe.work/ahttp"
"aahframe.work/essentials"
ess "aahframe.work/essentials"
"aahframe.work/internal/util"
"aahframe.work/security"
"aahframe.work/security/anticsrf"
Expand Down Expand Up @@ -198,7 +198,9 @@ func doAuthScheme(authScheme scheme.Schemer, ctx *Context) flowResult {
ctx.e.publishOnPreAuthEvent(ctx)

if doAuthentication(authScheme, ctx) == flowAbort {
ctx.Reply().Unauthorized().Error(newError(ErrAuthenticationFailed, http.StatusUnauthorized))
if ctx.Reply().err == nil {
ctx.Reply().Unauthorized().Error(newError(ErrAuthenticationFailed, http.StatusUnauthorized))
}
return flowAbort
}

Expand Down Expand Up @@ -241,6 +243,18 @@ func doAuthentication(authScheme scheme.Schemer, ctx *Context) flowResult {
ctx.Log().Infof("%s: Authentication is failed", authScheme.Key())
ctx.Reply().Header(ahttp.HeaderWWWAuthenticate, `Basic realm="`+sa.RealmName+`"`)
ctx.Reply().Unauthorized().Error(newError(ErrAuthenticationFailed, http.StatusUnauthorized))
case *scheme.GenericAuth:
switch err {
case authc.ErrAuthenticationFailed, authc.ErrAuthenticatorIsNil, authc.ErrPrincipalIsNil, authc.ErrSubjectNotExists:
ctx.Log().Infof("%s: Authentication is failed", authScheme.Key())
ctx.Reply().Unauthorized().Error(newError(ErrAuthenticationFailed, http.StatusUnauthorized))
case authc.ErrInternalServerError:
ctx.Log().Errorf("%s: Internal Server Error", authScheme.Key())
ctx.Reply().InternalServerError().Error(newError(err, http.StatusInternalServerError))
case authc.ErrServiceUnavailable:
ctx.Log().Errorf("%s: Service Unavailable", authScheme.Key())
ctx.Reply().ServiceUnavailable().Error(newError(err, http.StatusServiceUnavailable))
}
}

return flowAbort
Expand Down
8 changes: 7 additions & 1 deletion security/authc/authc.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"errors"

"aahframe.work/config"
"aahframe.work/essentials"
ess "aahframe.work/essentials"
)

var (
Expand All @@ -25,6 +25,12 @@ var (
// ErrSubjectNotExists error is returned when Subject is not exists in the application
// datasource.
ErrSubjectNotExists = errors.New("security/authc: subject not exists")

// ErrInternalServerError error is returned when we specifically want to return a 500 response code
ErrInternalServerError = errors.New("security/authc: internal server error")

// ErrServiceUnavailable error is returned when we specifically want to return a 503 response code
ErrServiceUnavailable = errors.New("security/authc: service unavailable")
)

// Authenticator interface is used to provide authentication information of application
Expand Down
1 change: 1 addition & 0 deletions security/authc/authentication_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type AuthenticationInfo struct {
IsLocked bool
IsExpired bool
Principals []*Principal
AuthenticationToken *AuthenticationToken
}

// PrimaryPrincipal method returns the primary Principal instance if principal
Expand Down
5 changes: 4 additions & 1 deletion security/authc/authentication_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ type AuthenticationToken struct {

// Credential is an account or subject secret.
Credential string

// Values contains additional information needed for authc and or authz phase
Values map[string]interface{}
}

// String method is stringer interface implementation.
func (a AuthenticationToken) String() string {
return fmt.Sprintf("authenticationtoken(scheme:%s identity:%s credential:*******)", a.Scheme, a.Identity)
return fmt.Sprintf("authenticationtoken(scheme:%s identity:%s credential:*******, values:%v)", a.Scheme, a.Identity, a.Values)
}
6 changes: 5 additions & 1 deletion security/authc/authentication_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ func TestAuthcAuthenticationToken(t *testing.T) {
Scheme: "form",
Identity: "jeeva",
Credential: "welcome123",
Values: map[string]interface{}{
"key1": "value 1",
"key2": "value 2",
},
}

assert.Equal(t, "authenticationtoken(scheme:form identity:jeeva credential:*******)", authToken.String())
assert.Equal(t, "authenticationtoken(scheme:form identity:jeeva credential:*******, values:map[key1:value 1 key2:value 2])", authToken.String())
}
6 changes: 4 additions & 2 deletions security/scheme/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

"aahframe.work/ahttp"
"aahframe.work/config"
"aahframe.work/essentials"
ess "aahframe.work/essentials"
"aahframe.work/log"
"aahframe.work/security/acrypto"
"aahframe.work/security/authc"
Expand Down Expand Up @@ -109,9 +109,11 @@ func (b *BaseAuth) DoAuthenticate(authcToken *authc.AuthenticationToken) (*authc
if err != nil {
log.Error(err)
}
return nil, authc.ErrAuthenticationFailed
return nil, err
}

// Propagate the authentication token
authcInfo.AuthenticationToken = authcToken
return authcInfo, nil
}

Expand Down
2 changes: 1 addition & 1 deletion security/scheme/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestSchemeBaseAuth(t *testing.T) {
authcToken := &authc.AuthenticationToken{}
authcInfo, err := baseAuth.DoAuthenticate(authcToken)
assert.NotNil(t, err)
assert.True(t, err == authc.ErrAuthenticationFailed)
assert.True(t, err == authc.ErrSubjectNotExists)
assert.Nil(t, authcInfo)

authcInfo, err = baseAuth.DoAuthenticate(nil)
Expand Down
11 changes: 10 additions & 1 deletion security/scheme/generic_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,18 @@ func (g *GenericAuth) Init(cfg *config.Config, keyName string) error {
return nil
}

// ExtractAuthenticationToken method extracts the authentication token information
type acauthenticator interface {
ExtractAuthenticationToken(r *ahttp.Request) *authc.AuthenticationToken
}

// ExtractAuthenticationToken method extracts an authentication token information
// from the HTTP request.
func (g *GenericAuth) ExtractAuthenticationToken(r *ahttp.Request) *authc.AuthenticationToken {
// Invoke the user provided method if exists for extracting authentication token
if ac, found := g.authenticator.(acauthenticator); found {
return ac.ExtractAuthenticationToken(r)
}

return &authc.AuthenticationToken{
Scheme: g.Scheme(),
Identity: r.Header.Get(g.IdentityHeader),
Expand Down

0 comments on commit 0bcfe2c

Please sign in to comment.