~bigbes/core-go

65b1657b30a1b1cf5ba7e926e2c060d3dabfe1cd — Simon Ser 3 years ago a941162
auth: add AuthContext.Access

Same logic as server.Access, but lower-level. Useful to check for
a permission not covered by the GraphQL schema @access directives
(such as builds.sr.ht secrets).
2 files changed, 31 insertions(+), 24 deletions(-)

M auth/middleware.go
M server/directives.go
M auth/middleware.go => auth/middleware.go +28 -0
@@ 84,6 84,34 @@ type AuthContext struct {
	TokenHash   [64]byte
}

func (authctx *AuthContext) Access(scope, kind string) error {
	switch authctx.AuthMethod {
	case AUTH_INTERNAL, AUTH_COOKIE:
		return nil
	case AUTH_OAUTH_LEGACY:
		if kind == RO {
			// Only legacy tokens with "*" scopes ever get this far
			return nil
		} else {
			return fmt.Errorf("Read/write access denied for legacy OAuth token")
		}
	case AUTH_WEBHOOK:
		if kind != RO {
			return fmt.Errorf("Access to read/write resolver denied for webhook")
		}
		fallthrough
	case AUTH_OAUTH2:
		if !authctx.Grants.Has(scope, kind) {
			return fmt.Errorf("Access denied, missing %v:%v grant", scope, kind)
		}
		return nil
	case AUTH_ANON_INTERNAL:
		return fmt.Errorf("Access denied for internal anonymous auth")
	default:
		panic(fmt.Errorf("Unknown auth method %q for access check", authctx.AuthMethod))
	}
}

func authError(w http.ResponseWriter, reason string, code int) {
	gqlerr := gqlerror.Errorf("Authentication error: %s", reason)
	b, err := json.Marshal(struct {

M server/directives.go => server/directives.go +3 -24
@@ 48,31 48,10 @@ func Private(ctx context.Context, obj interface{},

func Access(ctx context.Context, obj interface{}, next graphql.Resolver,
	scope string, kind string) (interface{}, error) {
	authctx := auth.ForContext(ctx)

	switch authctx.AuthMethod {
	case auth.AUTH_INTERNAL, auth.AUTH_COOKIE:
		return next(ctx)
	case auth.AUTH_OAUTH_LEGACY:
		if kind == auth.RO {
			// Only legacy tokens with "*" scopes ever get this far
			return next(ctx)
		}
	case auth.AUTH_WEBHOOK:
		if kind != auth.RO {
			return nil, fmt.Errorf("Access to read/write resolver denied for webhook")
		}
		fallthrough
	case auth.AUTH_OAUTH2:
		if !authctx.Grants.Has(scope, kind) {
			return nil, fmt.Errorf("Access denied, missing %v:%v grant", scope, kind)
		}
		return next(ctx)
	case auth.AUTH_ANON_INTERNAL:
		return nil, fmt.Errorf("Access denied for internal anonymous auth")
	default:
		panic(fmt.Errorf("Unknown auth method for access check"))
	if err := auth.ForContext(ctx).Access(scope, kind); err != nil {
		return nil, err
	}

	return nil, fmt.Errorf("Access denied for invalid auth method")
	return next(ctx)
}