// SignOut destroys the current session so that it cannot be used again func (s *realScope) SignOut(user *User) error { cl := multiclient.New().DefaultScopeFrom(s.getRpcScope()) cl.AddScopedReq(&multiclient.ScopedReq{ Uid: "deletesess", Service: loginService, Endpoint: deleteSessionEndpoint, Req: &sessdelproto.Request{ SessId: proto.String(user.SessId), }, Rsp: &sessdelproto.Response{}, }) if cl.Execute().AnyErrors() { return cl.Succeeded("deletesess") } if err := s.userCache.Purge(user.SessId); err != nil { log.Errorf("[Auth] Error purging session cache: %v", err) } s.Lock() defer s.Unlock() s.authUser = nil s.triedAuth = false return nil }
func (s *realScope) doAuth(mech, device string, creds map[string]string) (*User, error) { reqProto := &authproto.Request{ Mech: proto.String(mech), DeviceType: proto.String(device), Meta: make([]*loginproto.KeyValue, 0), } for k, v := range creds { switch k { case "username": reqProto.Username = proto.String(v) case "password": reqProto.Password = proto.String(v) case "newPassword": reqProto.NewPassword = proto.String(v) case "application": reqProto.Application = proto.String(v) default: // Add additional fields to Meta, such as DeviceId, osVersion, appVersion reqProto.Meta = append(reqProto.Meta, &loginproto.KeyValue{ Key: proto.String(k), Value: proto.String(v), }) } } cl := multiclient.New().DefaultScopeFrom(s.getRpcScope()) rsp := &authproto.Response{} cl.AddScopedReq(&multiclient.ScopedReq{ Uid: "auth", Service: loginService, Endpoint: authEndpoint, Req: reqProto, Rsp: rsp, Options: client.Options{"retries": 0}, }) if cl.Execute().AnyErrors() { // specfically map out bad credentials error err := cl.Succeeded("auth") if err.Code() == badCredentialsErrCode { return nil, BadCredentialsError } return nil, err } // recover this user u, err := FromSessionToken(rsp.GetSessId(), rsp.GetToken()) if err != nil { return nil, err } if err := s.userCache.Store(u); err != nil { log.Errorf("[Auth] Error caching session: %v", err) } return u, nil }
// doRecoverSession is the meat and veg for RecoverSession func (s *realScope) doRecoverSession(sessId string) (*User, error) { // Check cache; ignore errors (will have impact on service performance, but not functionality) queryLogin := false u, hit, err := s.userCache.Fetch(sessId) if err != nil { log.Warnf("[Auth] Error fetching session from cache (will call login service): %v", err) queryLogin = true } else if u != nil && u.ExpiryTs.Before(time.Now()) && u.CanAutoRenew() { // Cached token has expired log.Infof("[Auth] Cache-recovered token has expired (%s); will call login service", u.ExpiryTs.String()) queryLogin = true } else { queryLogin = u == nil && !hit } if queryLogin { cl := multiclient.New().DefaultScopeFrom(s.getRpcScope()) rsp := &sessreadproto.Response{} cl.AddScopedReq(&multiclient.ScopedReq{ Uid: "readsess", Service: loginService, Endpoint: readSessionEndpoint, Req: &sessreadproto.Request{ SessId: proto.String(sessId), }, Rsp: rsp, }) if cl.Execute().AnyErrorsIgnoring([]string{errors.ErrorNotFound}, nil) { err := cl.Succeeded("readsess") log.Errorf("[Auth] Auth scope recovery error [%s: %s] %v", err.Type(), err.Code(), err.Description()) return nil, err } // found a session? if rsp.GetSessId() == "" && rsp.GetToken() == "" { log.Debugf("[Auth] Session '%s' not found (not valid) when trying to recover from login service", sessId) // @todo we could cache this (at least for a short time) to prevent repeated hammering of login service } else { u, err = FromSessionToken(rsp.GetSessId(), rsp.GetToken()) if err != nil { log.Errorf("[Auth] Error getting user from session: %v", err) } else { log.Tracef("[Auth] Auth scope - recovered user '%s' from session '%s'", u.Id, rsp.GetSessId()) } } // ignore errors; just means we have no user if u != nil { s.userCache.Store(u) } } return u, nil }
// Call a service. No scoping/tracing yet. func Call(service, endpoint string, request, response proto.Message) error { call := multiclient.New().DefaultScopeFrom(server.Scoper()).AddScopedReq(&multiclient.ScopedReq{ Uid: "dummy", Service: service, Endpoint: endpoint, Req: request, Rsp: response, }).Execute() if call.AnyErrors() { return call.Succeeded("dummy") } return nil }