Skip to content

Commit

Permalink
cmd: Add ability to configure scope strategy
Browse files Browse the repository at this point in the history
Signed-off-by: arekkas <[email protected]>
  • Loading branch information
arekkas authored and aeneasr committed Aug 24, 2018
1 parent 61625bc commit 519a536
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 9 deletions.
8 changes: 8 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ before finalizing the upgrade process.

## 1.0.0-rc.1

### Scope Matching

Previously, `fosite.WildcardScopeStrategy` was used to validate OAuth 2.0 Scope. This is now configurable
with environment variables `AUTHENTICATOR_JWT_SCOPE_STRATEGY` and `AUTHENTICATOR_OAUTH2_INTROSPECTION_SCOPE_STRATEGY`.
Supported strategies are `HIERARCHIC`, `EXACT`, `WILDCARD`, `NONE`.

As part of this change, the default strategy is no longer `WILDCARD` but instead `EXACT`.

### Configuration changes

To improve compatibility with ORY Hydra v1.0.0-beta.8, which introduces the public and admin endpoint, the following
Expand Down
20 changes: 18 additions & 2 deletions cmd/helper_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,22 @@ func enabledHandlerNames() (d []string, e []string, f []string) {
return
}

func getScopeStrategy(key string) fosite.ScopeStrategy {
switch id := viper.GetString(key); id {
case "HIERARCHIC":
return fosite.HierarchicScopeStrategy
case "EXACT":
return fosite.ExactScopeStrategy
case "WILDCARD":
return fosite.WildcardScopeStrategy
case "NONE":
return nil
default:
logger.Fatalf(`scope strategy "%s" from config %s is unknown, only "HIERARCHIC", "EXACT", "WILDCARD", "NONE" are supported`, id, key)
}
return nil
}

func handlerFactories(keyManager rsakey.Manager) ([]proxy.Authenticator, []proxy.Authorizer, []proxy.CredentialsIssuer) {
var authorizers = []proxy.Authorizer{
proxy.NewAuthorizerAllow(),
Expand All @@ -187,14 +203,14 @@ func handlerFactories(keyManager rsakey.Manager) ([]proxy.Authenticator, []proxy
viper.GetString("AUTHENTICATOR_OAUTH2_INTROSPECTION_AUTHORIZATION_TOKEN_URL"),
viper.GetString("AUTHENTICATOR_OAUTH2_INTROSPECTION_URL"),
strings.Split(viper.GetString("AUTHENTICATOR_OAUTH2_INTROSPECTION_AUTHORIZATION_SCOPE"), ","),
fosite.WildcardScopeStrategy,
getScopeStrategy("AUTHENTICATOR_OAUTH2_INTROSPECTION_SCOPE_STRATEGY"),
),
proxy.NewAuthenticatorOAuth2ClientCredentials(
viper.GetString("AUTHENTICATOR_OAUTH2_CLIENT_CREDENTIALS_TOKEN_URL"),
),
proxy.NewAuthenticatorJWT(
viper.GetString("AUTHENTICATOR_JWT_JWKS_URL"),
fosite.WildcardScopeStrategy,
getScopeStrategy("AUTHENTICATOR_JWT_SCOPE_STRATEGY"),
),
},
authorizers,
Expand Down
3 changes: 3 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ func initConfig() {
viper.SetDefault("CREDENTIALS_ISSUER_ID_TOKEN_LIFESPAN", "10m")
viper.SetDefault("CREDENTIALS_ISSUER_ID_TOKEN_ISSUER", "http://localhost:"+viper.GetString("PORT"))

viper.SetDefault("AUTHENTICATOR_OAUTH2_INTROSPECTION_SCOPE_STRATEGY", "EXACT")
viper.SetDefault("AUTHENTICATOR_JWT_SCOPE_STRATEGY", "EXACT")

// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
Expand Down
11 changes: 11 additions & 0 deletions cmd/serve_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ AUTHENTICATORS
- AUTHENTICATOR_JWT_JWKS_URL: The URL where ORY Oathkeeper can retrieve JSON Web Keys from for validating
the JSON Web Token. Usually something like "https://my-keys.com/.well-known/jwks.json". The response
of that endpoint must return a JSON Web Key Set (JWKS).
- AUTHENTICATOR_JWT_SCOPE_STRATEGY: The strategy to be used to validate the scope claim. Strategies "HIERARCHIC", "EXACT",
"WILDCARD", "NONE" are supported. For more information on each strategy, go to http://www.ory.sh/docs.
--------------------------------------------------------------
Default: AUTHENTICATOR_JWT_SCOPE_STRATEGY=EXACT
--------------------------------------------------------------
- OAuth 2.0 Client Credentials Authenticator:
- AUTHENTICATOR_OAUTH2_CLIENT_CREDENTIALS_TOKEN_URL: Sets the OAuth 2.0 Token URL that should be used to check if
Expand All @@ -103,6 +108,12 @@ AUTHENTICATORS
Example: AUTHENTICATOR_OAUTH2_INTROSPECTION_INTROSPECT_URL=http://my-oauth2-server/oauth2/introspect
--------------------------------------------------------------
- AUTHENTICATOR_OAUTH2_INTROSPECTION_SCOPE_STRATEGY: The strategy to be used to validate the scope claim.
Strategies "HIERARCHIC", "EXACT", "WILDCARD", "NONE" are supported. For more information on each strategy, go to http://www.ory.sh/docs.
--------------------------------------------------------------
Default: AUTHENTICATOR_OAUTH2_INTROSPECTION_SCOPE_STRATEGY=EXACT
--------------------------------------------------------------
If the OAuth 2.0 Token Introspection Endpoint itself is protected with OAuth 2.0, you can provide the access credentials to perform
an OAuth 2.0 Client Credentials flow before accessing ORY Hydra's APIs.
Expand Down
5 changes: 5 additions & 0 deletions helper/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ var (
CodeField: http.StatusInternalServerError,
StatusField: http.StatusText(http.StatusInternalServerError),
}
ErrRuleFeatureDisabled = &herodot.DefaultError{
ErrorField: "The matched rule uses a feature which is not enabled in the server configuration",
CodeField: http.StatusInternalServerError,
StatusField: http.StatusText(http.StatusInternalServerError),
}
ErrMatchesNoRule = &herodot.DefaultError{
ErrorField: "Requested url does not match any rules",
CodeField: http.StatusNotFound,
Expand Down
20 changes: 13 additions & 7 deletions proxy/authenticator_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (a *AuthenticatorJWT) Authenticate(r *http.Request, config json.RawMessage,
case *jwt.SigningMethodHMAC:
return a.findSharedKey(token)
default:
return nil, errors.WithStack(helper.ErrUnauthorized.WithReason(fmt.Sprintf(`This request object uses unsupported signing algorithm "%s"."`, token.Header["alg"])))
return nil, errors.WithStack(helper.ErrUnauthorized.WithReason(fmt.Sprintf(`This request object uses unsupported signing algorithm "%s".`, token.Header["alg"])))
}
})

Expand All @@ -113,20 +113,26 @@ func (a *AuthenticatorJWT) Authenticate(r *http.Request, config json.RawMessage,

for _, audience := range cf.Audience {
if !stringslice.Has(parsedClaims.Audience, audience) {
return nil, errors.WithStack(helper.ErrForbidden.WithReason(fmt.Sprintf("Token audience %v is not intended for target audience %s", parsedClaims.Audience, audience)))
return nil, errors.WithStack(helper.ErrForbidden.WithReason(fmt.Sprintf("Token audience %v is not intended for target audience %s.", parsedClaims.Audience, audience)))
}
}

if len(cf.Issuers) > 0 {
if !stringslice.Has(cf.Issuers, parsedClaims.Issuer) {
return nil, errors.WithStack(helper.ErrForbidden.WithReason(fmt.Sprintf("Token issuer does not match any trusted issuer")))
return nil, errors.WithStack(helper.ErrForbidden.WithReason(fmt.Sprintf("Token issuer does not match any trusted issuer.")))
}
}

tokenScope := mapx.GetStringSliceDefault(map[interface{}]interface{}{"scope": claims["scope"]}, "scope", []string{})
for _, scope := range cf.Scopes {
if !a.scopeStrategy(tokenScope, scope) {
return nil, errors.WithStack(helper.ErrForbidden.WithReason(fmt.Sprintf("Token is missing required scope %s", scope)))
if a.scopeStrategy != nil {
tokenScope := mapx.GetStringSliceDefault(map[interface{}]interface{}{"scope": claims["scope"]}, "scope", []string{})
for _, scope := range cf.Scopes {
if !a.scopeStrategy(tokenScope, scope) {
return nil, errors.WithStack(helper.ErrForbidden.WithReason(fmt.Sprintf("Token is missing required scope %s.", scope)))
}
}
} else {
if len(cf.Scopes) > 0 {
return nil, errors.WithStack(helper.ErrRuleFeatureDisabled.WithReason("Scope validation was requested but scope strategy is set to \"NONE\"."))
}
}

Expand Down

0 comments on commit 519a536

Please sign in to comment.