func (s *grpcServer) Token(userID, clientID string, iat, exp time.Time) (*jose.JWT, string, error) { signer, err := s.server.KeyManager.Signer() if err != nil { log.Errorf("grpc.go: Failed to generate ID token: %v", err) return nil, "", oauth2.NewError(oauth2.ErrorServerError) } user, err := s.server.UserRepo.Get(nil, userID) if err != nil { log.Errorf("grpc.go: Failed to fetch user %q from repo: %v: ", userID, err) return nil, "", oauth2.NewError(oauth2.ErrorServerError) } claims := oidc.NewClaims(s.server.IssuerURL.String(), userID, clientID, iat, exp) user.AddToClaims(claims) if user.Admin { claims.Add(OtsimoUserTypeClaim, "adm") } jwt, err := jose.NewSignedJWT(claims, signer) if err != nil { log.Errorf("grpc.go: Failed to generate ID token: %v", err) return nil, "", oauth2.NewError(oauth2.ErrorServerError) } refreshToken, err := s.server.RefreshTokenRepo.Create(user.ID, clientID) if err != nil { log.Errorf("grpc.go: Failed to generate refresh token: %v", err) return nil, "", oauth2.NewError(oauth2.ErrorServerError) } return jwt, refreshToken, nil }
func (s *Server) ClientCredsToken(creds oidc.ClientCredentials) (*jose.JWT, error) { ok, err := s.ClientIdentityRepo.Authenticate(creds) if err != nil { log.Errorf("Failed fetching client %s from repo: %v", creds.ID, err) return nil, oauth2.NewError(oauth2.ErrorServerError) } if !ok { return nil, oauth2.NewError(oauth2.ErrorInvalidClient) } signer, err := s.KeyManager.Signer() if err != nil { log.Errorf("Failed to generate ID token: %v", err) return nil, oauth2.NewError(oauth2.ErrorServerError) } now := time.Now() exp := now.Add(s.SessionManager.ValidityWindow) claims := oidc.NewClaims(s.IssuerURL.String(), creds.ID, creds.ID, now, exp) claims.Add("name", creds.ID) jwt, err := jose.NewSignedJWT(claims, signer) if err != nil { log.Errorf("Failed to generate ID token: %v", err) return nil, oauth2.NewError(oauth2.ErrorServerError) } log.Infof("Client token sent: clientID=%s", creds.ID) return jwt, nil }
func (s *Server) handleClientRegistrationRequest(r *http.Request) (*oidc.ClientRegistrationResponse, *apiError) { var clientMetadata oidc.ClientMetadata if err := json.NewDecoder(r.Body).Decode(&clientMetadata); err != nil { return nil, newAPIError(oauth2.ErrorInvalidRequest, err.Error()) } if err := s.ProviderConfig().Supports(clientMetadata); err != nil { return nil, newAPIError(invalidClientMetadata, err.Error()) } // metadata is guarenteed to have at least one redirect_uri by earlier validation. id, err := oidc.GenClientID(clientMetadata.RedirectURIs[0].Host) if err != nil { log.Errorf("Faild to create client ID: %v", err) return nil, newAPIError(oauth2.ErrorServerError, "unable to save client metadata") } creds, err := s.ClientIdentityRepo.New(id, clientMetadata) if err != nil { log.Errorf("Failed to create new client identity: %v", err) return nil, newAPIError(oauth2.ErrorServerError, "unable to save client metadata") } return &oidc.ClientRegistrationResponse{ ClientID: creds.ID, ClientSecret: creds.Secret, ClientMetadata: clientMetadata, }, nil }
func (g *grpcServer) ChangeEmail(ctx context.Context, in *pb.ChangeEmailRequest) (*pb.Response, error) { jwtClient, err := getJWTToken(ctx) if err != nil { log.Errorf("grpc.go: getJWTToken error %v", err) return nil, err } _, _, err = g.authToken(jwtClient) if err != nil { log.Errorf("grpc.go: authToken failed error=%v", err) return nil, err } u, err := g.server.UserRepo.GetByEmail(nil, in.OldEmail) if err != nil { log.Errorf("grpc.go: change email user not found =%v", err) return nil, err } err = g.server.UserRepo.Update(nil, user.User{ ID: u.ID, Email: in.NewEmail, }) if err != nil { log.Errorf("grpc.go: failed to change email of user %+v", err) return nil, err } return &pb.Response{Type: 0}, nil }
func (r *clientIdentityRepo) Authenticate(creds oidc.ClientCredentials) (bool, error) { m, err := r.executor(nil).Get(clientIdentityModel{}, creds.ID) if m == nil || err != nil { return false, err } cim, ok := m.(*clientIdentityModel) if !ok { log.Errorf("expected clientIdentityModel but found %v", reflect.TypeOf(m)) return false, errors.New("unrecognized model") } dec, err := base64.URLEncoding.DecodeString(creds.Secret) if err != nil { log.Errorf("error Decoding client creds: %v", err) return false, nil } if len(dec) > maxSecretLength { return false, nil } ok = bcrypt.CompareHashAndPassword(cim.Secret, dec) == nil return ok, nil }
func registerUser(o *OtsimoAccounts, email, password, firstName, lastName, language string) (*pb.RegisterResponse, error) { resp, err := o.Dex.Register(context.Background(), &pb.RegisterRequest{ Email: email, DisplayName: fmt.Sprintf("%s %s", firstName, lastName), Password: password, }) log.Infof("register.go: register result of '%s' is %q %v", email, resp, err) if err != nil { return nil, err } _, errapi := o.Api.AddProfile(context.Background(), &apipb.Profile{ Id: bson.ObjectIdHex(resp.UserId), Email: email, FirstName: firstName, LastName: lastName, Language: language, }) if errapi != nil { //Disable or delete user log.Errorf("register.go: failed to add profile %+v", errapi) _, err = o.Dex.RemoveUser(context.Background(), &pb.RemoveRequest{Id: resp.UserId, Email: email}) if err != nil { log.Errorf("register.go: Holly F**K!!: failed to add profile and remove user [error]=%+v [user_id]='%s' [user_email]='%s'", err, resp.UserId, email) return nil, err } return nil, fmt.Errorf("failed to register user, adding to api service failed:%v", errapi) } return resp, nil }
func (g *grpcServer) RemoveUser(ctx context.Context, in *pb.RemoveRequest) (*pb.Response, error) { jwtClient, err := getJWTToken(ctx) if err != nil { log.Errorf("grpc.go: getJWTToken error %v", err) return nil, err } _, _, err = g.authToken(jwtClient) if err != nil { log.Errorf("grpc.go: authToken failed error=%v", err) return nil, err } usr, err := g.server.UserManager.Get(in.Id) if err != nil { log.Errorf("grpc.go: failed to get user %+v", err) return nil, err } if usr.Email == in.Email { return nil, errors.New("given email is different than old one") } err = g.server.UserRepo.Update(nil, user.User{ ID: in.Id, Email: fmt.Sprintf("$$%s$%s", randStringBytesRmndr(4), in.Email), Disabled: false, }) if err != nil { log.Errorf("grpc.go: failed to update-remove user %+v", err) return nil, err } return &pb.Response{Type: 0}, nil }
func (s *Server) RefreshToken(creds oidc.ClientCredentials, token string) (*jose.JWT, error) { ok, err := s.ClientIdentityRepo.Authenticate(creds) if err != nil { log.Errorf("Failed fetching client %s from repo: %v", creds.ID, err) return nil, oauth2.NewError(oauth2.ErrorServerError) } if !ok { log.Errorf("Failed to Authenticate client %s", creds.ID) return nil, oauth2.NewError(oauth2.ErrorInvalidClient) } userID, err := s.RefreshTokenRepo.Verify(creds.ID, token) switch err { case nil: break case refresh.ErrorInvalidToken: return nil, oauth2.NewError(oauth2.ErrorInvalidRequest) case refresh.ErrorInvalidClientID: return nil, oauth2.NewError(oauth2.ErrorInvalidClient) default: return nil, oauth2.NewError(oauth2.ErrorServerError) } user, err := s.UserRepo.Get(nil, userID) if err != nil { // The error can be user.ErrorNotFound, but we are not deleting // user at this moment, so this shouldn't happen. log.Errorf("Failed to fetch user %q from repo: %v: ", userID, err) return nil, oauth2.NewError(oauth2.ErrorServerError) } signer, err := s.KeyManager.Signer() if err != nil { log.Errorf("Failed to refresh ID token: %v", err) return nil, oauth2.NewError(oauth2.ErrorServerError) } now := time.Now() expireAt := now.Add(session.DefaultSessionValidityWindow) claims := oidc.NewClaims(s.IssuerURL.String(), user.ID, creds.ID, now, expireAt) user.AddToClaims(claims) jwt, err := jose.NewSignedJWT(claims, signer) if err != nil { log.Errorf("Failed to generate ID token: %v", err) return nil, oauth2.NewError(oauth2.ErrorServerError) } log.Infof("New token sent: clientID=%s", creds.ID) return jwt, nil }
// writeResponseWithBody attempts to marshal an arbitrary thing to JSON then write // it to the http.ResponseWriter func writeResponseWithBody(w http.ResponseWriter, code int, resp interface{}) { enc, err := json.Marshal(resp) if err != nil { log.Errorf("Failed JSON-encoding HTTP response: %v", err) w.WriteHeader(http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) if _, err = w.Write(enc); err != nil { log.Errorf("Failed writing HTTP response: %v", err) } }
func (u *UserEmailer) signedClaimsToken(claims jose.Claims) (string, error) { signer, err := u.signerFn() if err != nil || signer == nil { log.Errorf("error getting signer: %v (%v)", err, signer) return "", err } jwt, err := jose.NewSignedJWT(claims, signer) if err != nil { log.Errorf("error constructing or signing a JWT: %v", err) return "", err } return jwt.Encode(), nil }
func (c *clientResource) create(w http.ResponseWriter, r *http.Request) { ct := r.Header.Get("content-type") if ct != "application/json" { log.Debugf("Unsupported request content-type: %v", ct) writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidRequest, "unsupported content-type")) return } var sc schema.Client dec := json.NewDecoder(r.Body) err := dec.Decode(&sc) if err != nil { log.Debugf("Error decoding request body: %v", err) writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidRequest, "unable to decode request body")) return } ci, err := schema.MapSchemaClientToClientIdentity(sc) if err != nil { log.Debugf("Invalid request data: %v", err) writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidClientMetadata, "missing or invalid field: redirectURIs")) return } if err := ci.Metadata.Valid(); err != nil { log.Debugf("ClientMetadata invalid: %v", err) writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidClientMetadata, err.Error())) return } clientID, err := oidc.GenClientID(ci.Metadata.RedirectURIs[0].Host) if err != nil { log.Errorf("Failed generating ID for new client: %v", err) writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError, "unable to generate client ID")) return } creds, err := c.repo.New(clientID, ci.Metadata) if err != nil { log.Errorf("Failed creating client: %v", err) writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError, "unable to create client")) return } ci.Credentials = *creds ssc := schema.MapClientIdentityToSchemaClientWithSecret(ci) w.Header().Add("Location", phttp.NewResourceLocation(r.URL, ci.Credentials.ID)) writeResponseWithBody(w, http.StatusCreated, ssc) }
func (h *SendResetPasswordEmailHandler) exchangeKeyForClientAndRedirect(key string) (string, url.URL, error) { id, err := h.sm.ExchangeKey(key) if err != nil { log.Errorf("error exchanging key: %v ", err) return "", url.URL{}, err } ses, err := h.sm.Kill(id) if err != nil { log.Errorf("error killing session: %v", err) return "", url.URL{}, err } return ses.ClientID, ses.RedirectURL, nil }
func (u *UserEmailer) userPasswordInfo(email string) (user.User, user.PasswordInfo, error) { usr, err := u.ur.GetByEmail(nil, email) if err != nil { log.Errorf("Error getting user: %q", err) return user.User{}, user.PasswordInfo{}, err } pwi, err := u.pwi.Get(nil, usr.ID) if err != nil { log.Errorf("Error getting password: %q", err) return user.User{}, user.PasswordInfo{}, err } return usr, pwi, nil }
func (c *OAuth2Connector) handleCallbackFunc(lf oidc.LoginFunc, errorURL url.URL) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() e := q.Get("error") if e != "" { redirectError(w, errorURL, q) return } code := q.Get("code") if code == "" { q.Set("error", oauth2.ErrorInvalidRequest) q.Set("error_description", "code query param must be set") redirectError(w, errorURL, q) return } sessionKey := q.Get("state") token, err := c.conn.Client().RequestToken(oauth2.GrantTypeAuthCode, code) if err != nil { log.Errorf("Unable to verify auth code with issuer: %v", err) q.Set("error", oauth2.ErrorUnsupportedResponseType) q.Set("error_description", "unable to verify auth code with issuer") redirectError(w, errorURL, q) return } ident, err := c.conn.Identity(newAuthenticatedClient(token, http.DefaultClient)) if err != nil { log.Errorf("Unable to retrieve identity: %v", err) q.Set("error", oauth2.ErrorUnsupportedResponseType) q.Set("error_description", "unable to retrieve identity from issuer") redirectError(w, errorURL, q) return } redirectURL, err := lf(ident, sessionKey) if err != nil { log.Errorf("Unable to log in %#v: %v", ident, err) q.Set("error", oauth2.ErrorAccessDenied) q.Set("error_description", "login failed") redirectError(w, errorURL, q) return } w.Header().Set("Location", redirectURL) w.WriteHeader(http.StatusFound) return } }
func (h *SendResetPasswordEmailHandler) handleGET(w http.ResponseWriter, r *http.Request) { sessionKey := r.URL.Query().Get("session_key") if sessionKey != "" { clientID, redirectURL, err := h.exchangeKeyForClientAndRedirect(sessionKey) if err == nil { handleURL := *r.URL q := r.URL.Query() q.Del("session_key") q.Set("redirect_uri", redirectURL.String()) q.Set("client_id", clientID) handleURL.RawQuery = q.Encode() http.Redirect(w, r, handleURL.String(), http.StatusSeeOther) return } // Even though we could not exchange the sessionKey to get a // redirect URL, we can still continue as if they didn't pass // one in, so we don't return here. log.Errorf("could not exchange sessionKey: %v", err) } data := sendResetPasswordEmailData{} if err := h.fillData(r, &data); err != nil { writeAPIError(w, http.StatusBadRequest, err) } if data.ClientID == "" { writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidRequest, "missing required parameters")) return } execTemplate(w, h.tpl, data) }
func (r *userRepo) GetRemoteIdentities(tx repo.Transaction, userID string) ([]user.RemoteIdentity, error) { ex := r.executor(tx) if userID == "" { return nil, user.ErrorInvalidID } qt := r.quote(remoteIdentityMappingTableName) rims, err := ex.Select(&remoteIdentityMappingModel{}, fmt.Sprintf("SELECT * FROM %s WHERE user_id = $1", qt), userID) if err != nil { if err != sql.ErrNoRows { return nil, err } return nil, nil } if len(rims) == 0 { return nil, nil } var ris []user.RemoteIdentity for _, m := range rims { rim, ok := m.(*remoteIdentityMappingModel) if !ok { log.Errorf("expected remoteIdentityMappingModel but found %v", reflect.TypeOf(m)) return nil, errors.New("unrecognized model") } ris = append(ris, user.RemoteIdentity{ ID: rim.RemoteID, ConnectorID: rim.ConnectorID, }) } return ris, nil }
func (c *LDAPConnector) Groups(fullUserID string) ([]string, error) { if !c.searchBeforeAuth { return nil, fmt.Errorf("cannot search without service account") } if c.searchGroupFilter == "" { return nil, fmt.Errorf("no group filter specified") } var groups []string err := c.ldapPool.Do(func(conn *ldap.Conn) error { if err := conn.Bind(c.searchBindDN, c.searchBindPw); err != nil { if !invalidBindCredentials(err) { log.Errorf("failed to connect to LDAP for search bind: %v", err) } return fmt.Errorf("failed to bind: %v", err) } req := &ldap.SearchRequest{ BaseDN: c.baseDN, Scope: c.searchScope, Filter: c.formatDN(c.searchGroupFilter, fullUserID), } resp, err := conn.Search(req) if err != nil { return fmt.Errorf("search failed: %v", err) } groups = make([]string, len(resp.Entries)) for i, entry := range resp.Entries { groups[i] = entry.DN } return nil }) return groups, err }
func (r *clientIdentityRepo) SetDexAdmin(clientID string, isAdmin bool) error { tx, err := r.begin() if err != nil { return err } defer tx.Rollback() exec := r.executor(tx) m, err := exec.Get(clientIdentityModel{}, clientID) if m == nil || err != nil { return err } cim, ok := m.(*clientIdentityModel) if !ok { log.Errorf("expected clientIdentityModel but found %v", reflect.TypeOf(m)) return errors.New("unrecognized model") } cim.DexAdmin = isAdmin _, err = exec.Update(cim) if err != nil { return err } return tx.Commit() }
func (r *clientIdentityRepo) SetDexAdmin(clientID string, isAdmin bool) error { tx, err := r.dbMap.Begin() if err != nil { return err } m, err := r.dbMap.Get(clientIdentityModel{}, clientID) if m == nil || err != nil { rollback(tx) return err } cim, ok := m.(*clientIdentityModel) if !ok { rollback(tx) log.Errorf("expected clientIdentityModel but found %v", reflect.TypeOf(m)) return errors.New("unrecognized model") } cim.DexAdmin = isAdmin _, err = r.dbMap.Update(cim) if err != nil { rollback(tx) return err } err = tx.Commit() if err != nil { rollback(tx) return err } return nil }
func handleOOBFunc(s *Server, tpl *template.Template) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { w.Header().Set("Allow", "GET") phttp.WriteError(w, http.StatusMethodNotAllowed, "GET only acceptable method") return } key := r.URL.Query().Get("code") if key == "" { phttp.WriteError(w, http.StatusBadRequest, "Invalid Session") return } sessionID, err := s.SessionManager.ExchangeKey(key) if err != nil { phttp.WriteError(w, http.StatusBadRequest, "Invalid Session") return } code, err := s.SessionManager.NewSessionKey(sessionID) if err != nil { log.Errorf("problem getting NewSessionKey: %v", err) phttp.WriteError(w, http.StatusInternalServerError, "Internal Server Error") return } execTemplate(w, tpl, map[string]string{ "code": code, }) } }
func (r *SessionKeyRepo) Pop(key string) (string, error) { m, err := r.dbMap.Get(sessionKeyModel{}, key) if err != nil { return "", err } skm, ok := m.(*sessionKeyModel) if !ok { return "", errors.New("unrecognized model") } if skm.Stale || skm.ExpiresAt < r.clock.Now().Unix() { return "", errors.New("invalid session key") } qt := pq.QuoteIdentifier(sessionKeyTableName) q := fmt.Sprintf("UPDATE %s SET stale=$1 WHERE key=$2 AND stale=$3", qt) res, err := r.dbMap.Exec(q, true, key, false) if err != nil { return "", err } if n, err := res.RowsAffected(); n != 1 { if err != nil { log.Errorf("Failed determining rows affected by UPDATE session_key query: %v", err) } return "", fmt.Errorf("failed to pop entity") } return skm.SessionID, nil }
// addClaimsFromScope adds claims that are based on the scopes that the client requested. // Currently, these include cross-client claims (aud, azp). func (s *Server) addClaimsFromScope(claims jose.Claims, scopes scope.Scopes, clientID string) error { crossClientIDs := scopes.CrossClientIDs() if len(crossClientIDs) > 0 { var aud []string for _, id := range crossClientIDs { if clientID == id { aud = append(aud, id) continue } allowed, err := s.CrossClientAuthAllowed(clientID, id) if err != nil { log.Errorf("Failed to check cross client auth. reqClientID %v; authClient:ID %v; err: %v", clientID, id, err) return oauth2.NewError(oauth2.ErrorServerError) } if !allowed { err := oauth2.NewError(oauth2.ErrorInvalidRequest) err.Description = fmt.Sprintf( "%q is not authorized to perform cross-client requests for %q", clientID, id) return err } aud = append(aud, id) } if len(aud) == 1 { claims.Add("aud", aud[0]) } else { claims.Add("aud", aud) } claims.Add("azp", clientID) } return nil }
func handleResendFunc(o *OtsimoAccounts, issuerURL, resendURL, cbURL url.URL) http.HandlerFunc { trans := &oidc.AuthenticatedTransport{ TokenRefresher: &ClientCredsTokenRefresher{ Issuer: issuerURL.String(), OIDCClient: o.Oidc, }, RoundTripper: http.DefaultTransport, } hc := &http.Client{Transport: trans} return func(w http.ResponseWriter, r *http.Request) { r.ParseForm() tok := r.Form.Get("jwt") q := struct { Token string `json:"token"` RedirectURI string `json:"redirectURI"` }{ Token: tok, RedirectURI: cbURL.String(), } qBytes, err := json.Marshal(&q) res, err := hc.Post(resendURL.String(), "application/json", bytes.NewReader(qBytes)) if err != nil { log.Errorf("error requesting email resend: %v", err) writeError(w, http.StatusInternalServerError, "error requesting email resend") return } w.Write([]byte(fmt.Sprintf("Status from Dex: %v", res.Status))) } }
func (gc *GarbageCollector) Run() chan struct{} { stop := make(chan struct{}) go func() { var failing bool next := gc.interval for { select { case <-gc.clock.After(next): if anyPurgeErrors(purgeAll(gc.purgers)) { if !failing { failing = true next = time.Second } else { next = ptime.ExpBackoff(next, time.Minute) } log.Errorf("Failed garbage collection, retrying in %v", next) } else { failing = false next = gc.interval log.Infof("Garbage collection complete, running again in %v", next) } case <-stop: return } } }() return stop }
func (r *SessionRepo) Get(sessionID string) (*session.Session, error) { m, err := r.dbMap.Get(sessionModel{}, sessionID) if err != nil { return nil, err } if m == nil { return nil, errors.New("session does not exist") } sm, ok := m.(*sessionModel) if !ok { log.Errorf("expected sessionModel but found %v", reflect.TypeOf(m)) return nil, errors.New("unrecognized model") } ses, err := sm.session() if err != nil { return nil, err } if ses.ExpiresAt.Before(r.clock.Now()) { return nil, errors.New("session does not exist") } return ses, nil }
func anyPurgeErrors(errchan <-chan purgeError) (found bool) { for perr := range errchan { found = true log.Errorf("Failed purging %s: %v", perr.name, perr.err) } return }
// SendResetPasswordEmail sends a password reset email to the user specified by the email addresss, containing a link with a signed token which can be visitied to initiate the password change/reset process. // This method DOES NOT check for client ID, redirect URL validity - it is expected that upstream users have already done so. // A link that can be used to reset the given user's password is returned. func (u *UserEmailer) SendResetPasswordEmail(email string, redirectURL url.URL, clientID string) (*url.URL, error) { usr, pwi, err := u.userPasswordInfo(email) if err != nil { return nil, err } passwordReset := user.NewPasswordReset(usr.ID, pwi.Password, u.issuerURL, clientID, redirectURL, u.tokenValidityWindow) token, err := u.signedClaimsToken(passwordReset.Claims) if err != nil { return nil, err } resetURL := u.passwordResetURL q := resetURL.Query() q.Set("token", token) resetURL.RawQuery = q.Encode() if u.emailer != nil { err = u.emailer.SendMail(u.fromAddress, "Reset Your Password", "password-reset", map[string]interface{}{ "email": usr.Email, "link": resetURL.String(), }, usr.Email) if err != nil { log.Errorf("error sending password reset email %v: ", err) } return nil, err } return &resetURL, nil }
// SendInviteEmail is sends an email that allows the user to both // reset their password *and* verify their email address. Similar to // SendResetPasswordEmail, the given url and client id are assumed // valid. A link that can be used to validate the given email address // and reset the password is returned. func (u *UserEmailer) SendInviteEmail(email string, redirectURL url.URL, clientID string) (*url.URL, error) { usr, pwi, err := u.userPasswordInfo(email) if err != nil { return nil, err } invitation := user.NewInvitation(usr, pwi.Password, u.issuerURL, clientID, redirectURL, u.tokenValidityWindow) token, err := u.signedClaimsToken(invitation.Claims) if err != nil { return nil, err } resetURL := u.invitationURL q := resetURL.Query() q.Set("token", token) resetURL.RawQuery = q.Encode() if u.emailer != nil { err = u.emailer.SendMail("Activate Your Account", "invite", map[string]interface{}{ "email": usr.Email, "link": resetURL.String(), }, usr.Email) if err != nil { log.Errorf("error sending password reset email %v: ", err) } return nil, err } return &resetURL, nil }
func handleRegisterFunc(o *OtsimoAccounts) http.HandlerFunc { handlePOST := func(w http.ResponseWriter, r *http.Request) { r.ParseForm() email := r.PostFormValue("username") password := r.PostFormValue("password") firstName := r.PostFormValue("first_name") lastName := r.PostFormValue("last_name") language := r.PostFormValue("language") if email == "" || password == "" { writeError(w, http.StatusBadRequest, "invalid body") return } result, err := registerUser(o, email, password, firstName, lastName, language) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeResponseWithBody(w, http.StatusOK, result.Token) } handleGET := func(w http.ResponseWriter, r *http.Request) { oac, err := o.Oidc.OAuthClient() if err != nil { log.Errorf("failed to create OAuthClient %v", err) writeError(w, http.StatusInternalServerError, err.Error()) } u, err := url.Parse(oac.AuthCodeURL("", "", "")) q := u.Query() q.Set("register", "1") if err != nil { log.Errorf("failed to create authCoreURL %v", err) writeError(w, http.StatusInternalServerError, err.Error()) } u.RawQuery = q.Encode() log.Infof("URL: %v", u.String()) http.Redirect(w, r, u.String(), http.StatusFound) } return func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { handlePOST(w, r) } else if r.Method == "GET" { handleGET(w, r) } else { writeError(w, http.StatusNotFound, "wrong Http Verb") } } }
func (s *grpcServer) authToken(jwt jose.JWT) (string, *oidc.ClientMetadata, error) { ciRepo := s.server.ClientIdentityRepo keys, err := s.server.KeyManager.PublicKeys() if err != nil { log.Errorf("grpc.go: Failed to get keys: %v", err) return "", nil, errors.New("errorAccessDenied") } if len(keys) == 0 { log.Error("grpc.go: No keys available for verification client") return "", nil, errors.New("errorAccessDenied") } ok, err := oidc.VerifySignature(jwt, keys) if err != nil { log.Errorf("grpc.go: Failed to verify signature: %v", err) return "", nil, err } if !ok { log.Info("grpc.go: token signature is not verified") return "", nil, errors.New("invalid token") } clientID, err := oidc.VerifyClientClaims(jwt, s.server.IssuerURL.String()) if err != nil { log.Errorf("grpc.go: Failed to verify JWT claims: %v", err) return "", nil, errors.New("failed to verify jwt claims token") } md, err := ciRepo.Metadata(clientID) if md == nil || err != nil { log.Errorf("grpc.go: Failed to find clientID: %s, error=%v", clientID, err) return "", nil, err } //client must be admin in order to use login and register grpc apis. ok, err = ciRepo.IsDexAdmin(clientID) if err != nil { return "", nil, err } if !ok { log.Infof("grpc.go: Client [%s] is not admin", clientID) return "", nil, errors.New("errorAccessDenied") } log.Debugf("grpc.go: Authenticated token for client ID %s", clientID) return clientID, md, nil }