// Authorise tests auth func (a *simpleAuthoriser) Authorise(req *Request) errors.Error { // If we require neither a role or a user, then there is no need to authorise if !a.requireUser && !a.requireRole { log.Debugf("Skipping auth from %s to %s, as neither user or role required", req.From(), req.Destination()) return nil } // Otherwise, authorise this request scope := req.Auth() log.Tracef("Scope user: %v", scope.AuthUser()) if a.requireUser && !scope.IsAuth() { return errors.Forbidden("com.hailocab.kernel.auth.notsignedin", fmt.Sprintf("Must be signed in to call this endpoint[endpoint=%s, service=%s, from=%s]", req.Endpoint(), req.Service(), req.From()), "201") } if a.requireRole { matchesRole := false for _, r := range a.roles { if scope.HasAccess(r) { matchesRole = true break } } if !matchesRole { if scope.HasTriedAuth() { return errors.Forbidden("com.hailocab.kernel.auth.badrole", fmt.Sprintf("Must be signed in to call this endpoint[endpoint=%s, service=%s, from=%s]", req.Endpoint(), req.Service(), req.From()), "201") } // Instrument when service to service auth fails inst.Counter(1.0, "auth.servicetoservice.failed", 1) return BadRoleError(req) } } return nil }
func TestErrorCaller(t *testing.T) { err := errors.Forbidden("foo.bar.baz", "Oh noes!") caller := ErrorCaller(err) e := caller(nil, nil) if e == nil { t.Fatalf("ErrorCaller should have returned the error we gave it") } if e.Code() != "foo.bar.baz" { t.Errorf("Error code should be foo.bar.baz") } }
// TestAuthHappyCaseValid tests when things work, and when the credentials are bad func (suite *sessionRecoverySuite) TestAuthHappyCaseInvalid() { t := suite.T() scope := New().(*realScope) scope.userCache = newTestCache() mock := multiclient.NewMock() stub := &multiclient.Stub{ Service: loginService, Endpoint: authEndpoint, Error: errors.Forbidden("com.hailocab.service.login.auth.badCredentials", "Bad credentials"), } mock.Stub(stub) multiclient.SetCaller(mock.Caller()) testMech, testDeviceType := "h2", "cli" testUsername, testPassword := "******", "Securez1" testCreds := map[string]string{ "username": testUsername, "password": testPassword, } err := scope.Auth(testMech, testDeviceType, testCreds) if err == nil { t.Fatal("Expecting auth error") } if err != BadCredentialsError { t.Errorf("Expecting auth error to be BadCredentialsError; got %v", err) } if scope.IsAuth() { t.Error("Expecting scope to be IsAuth==false after bad credentials auth") } if !scope.HasTriedAuth() { t.Error("Expecting scope to have HasTriedAuth()==true after bad credentials auth") } if u := scope.AuthUser(); u != nil { t.Error("Expecting AuthUser()==nil after bad credentials auth") } // verify we made correct request(s) if stub.CountCalls() != 1 { t.Fatalf("Expecting 1 call to auth; got %v", stub.CountCalls()) } }
func (suite *multiClientSuite) TestSetCallerAndReset() { cl := &defClient{ requests: make(map[string]*client.Request), responses: make(map[string]proto.Message), errors: &errorsImpl{}, } c := ErrorCaller(errors.Forbidden("bad.person", "Much forbid")) cl.SetCaller(c) suite.Assertions.NotNil(cl.caller, "Set caller did not update caller :(") // do a call! cl.AddScopedReq(&ScopedReq{ Service: "com.hailocab.service.foo", Endpoint: "health", Req: &hcproto.Request{}, Rsp: &hcproto.Response{}, }) cl.Execute() err := cl.Succeeded("") suite.Assertions.NotNil(err, "Error caller we set did not result in error!") suite.Assertions.Equal("bad.person", err.Code()) // now we should be able to RESET this, and use the _same_ caller again suite.Assertions.True(cl.AnyErrors(), "Expecting us to HAVE errors, before we reset") suite.Assertions.False(cl.Reset().AnyErrors(), "Expecting us NOT to have errors, after we reset") // make same call -- crucial point is that the SetCaller thing shouldn't be reset cl.AddScopedReq(&ScopedReq{ Service: "com.hailocab.service.foo", Endpoint: "health", Req: &hcproto.Request{}, Rsp: &hcproto.Response{}, }) cl.Execute() err = cl.Succeeded("") suite.Assertions.NotNil(err, "Error caller we set did not result in error!") suite.Assertions.Equal("bad.person", err.Code()) }
func (suite *multiClientSuite) TestSucceeded() { cl := &defClient{ requests: make(map[string]*client.Request), responses: make(map[string]proto.Message), errors: &errorsImpl{}, } cl.SetCaller(ErrorCaller(errors.Forbidden("bad.person", "Much forbid"))) // A single request should not add any context to the code cl.DefaultScopeFrom(ExplicitScoper().SetContext("prefixy")) cl.AddScopedReq(&ScopedReq{ Service: "com.hailocab.service.foo", Endpoint: "health", Req: &hcproto.Request{}, Rsp: &hcproto.Response{}, }) cl.Execute() err := cl.Succeeded("") suite.Assertions.NotNil(err) suite.Assertions.True(errors.IsForbidden(err)) suite.Assertions.Equal("bad.person", err.Code()) suite.Assertions.Equal("Much forbid", err.Description()) }
func (suite *multiClientSuite) TestPlatformError() { cl := &defClient{ requests: make(map[string]*client.Request), responses: make(map[string]proto.Message), errors: &errorsImpl{}, } cl.SetCaller(ErrorCaller(errors.Forbidden("bad.person", "Much forbid"))) // A single request should not add the suffix provided to PlatformError() but return it verbatim cl.AddScopedReq(&ScopedReq{ Service: "com.hailocab.service.foo", Endpoint: "health", Req: &hcproto.Request{}, Rsp: &hcproto.Response{}, }) cl.Execute() err := cl.PlatformError("suffixy") suite.Assertions.NotNil(err) suite.Assertions.True(errors.IsForbidden(err)) suite.Assertions.Equal("bad.person", err.Code()) suite.Assertions.Equal("Much forbid", err.Description()) // Multiple errors should use the suffix provided cl.Reset() cl.AddScopedReq(&ScopedReq{ Uid: "uid1", Service: "com.hailocab.service.foo", Endpoint: "health", Req: &hcproto.Request{}, Rsp: &hcproto.Response{}, }) cl.AddScopedReq(&ScopedReq{ Uid: "uid2", Service: "com.hailocab.service.foo", Endpoint: "bar", Req: &hcproto.Request{}, Rsp: &hcproto.Response{}, }) cl.Execute() err = cl.PlatformError("suffixy") suite.Assertions.NotNil(err) suite.Assertions.True(errors.IsInternalServerError(err)) suite.Assertions.Equal("suffixy", err.Code()) // Multiple errors with a defaultScopeFrom should join the two cl.Reset() cl.DefaultScopeFrom(ExplicitScoper().SetContext("prefixy")) cl.AddScopedReq(&ScopedReq{ Uid: "uid1", Service: "com.hailocab.service.foo", Endpoint: "health", Req: &hcproto.Request{}, Rsp: &hcproto.Response{}, }) cl.AddScopedReq(&ScopedReq{ Uid: "uid2", Service: "com.hailocab.service.foo", Endpoint: "bar", Req: &hcproto.Request{}, Rsp: &hcproto.Response{}, }) cl.Execute() err = cl.PlatformError("suffixy") suite.Assertions.NotNil(err) suite.Assertions.True(errors.IsInternalServerError(err)) suite.Assertions.Equal("prefixy.suffixy", err.Code()) }
// Given a request, returns a "bad role" error. This is used both by Authorise() and is useful within services which do // row-level permission checking. func BadRoleError(req *Request) errors.Error { return errors.Forbidden("com.hailocab.kernel.auth.badrole", fmt.Sprintf("Must have the correct role to call this "+ "endpoint [endpoint=%s, service=%s, from=%s]", req.Endpoint(), req.Service(), req.From()), "5") }