lot of new functionalities
This commit is contained in:
240
core/application/auth.go
Normal file
240
core/application/auth.go
Normal file
@@ -0,0 +1,240 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"git.coopgo.io/coopgo-platform/groups-management/grpcapi"
|
||||
mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
|
||||
ma "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
|
||||
groupsstorage "git.coopgo.io/coopgo-platform/groups-management/storage"
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type OAuth2CallbackResult struct {
|
||||
RedirectURL string
|
||||
IDToken string
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) ProcessOAuth2Callback(code string, redirectSession string) (*OAuth2CallbackResult, error) {
|
||||
oauth2Token, err := h.idp.OAuth2Config.Exchange(context.Background(), code)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Exchange error")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Extract the ID Token from OAuth2 token.
|
||||
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
log.Error().Msg("Cannot retrieve ID token")
|
||||
return nil, errors.New("cannot retrieve ID token")
|
||||
}
|
||||
|
||||
_, err = h.idp.TokenVerifier.Verify(context.Background(), rawIDToken)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Not able to verify token")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
redirect := "/app/"
|
||||
if redirectSession != "" {
|
||||
redirect = redirectSession
|
||||
}
|
||||
|
||||
return &OAuth2CallbackResult{
|
||||
RedirectURL: redirect,
|
||||
IDToken: rawIDToken,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type LostPasswordInitResult struct {
|
||||
Success bool
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) InitiateLostPassword(email string) (*LostPasswordInitResult, error) {
|
||||
account, err := h.services.GRPC.MobilityAccounts.GetAccountUsername(context.TODO(), &mobilityaccounts.GetAccountUsernameRequest{
|
||||
Username: email,
|
||||
Namespace: "parcoursmob",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b := make([]byte, 16)
|
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := base64.RawURLEncoding.EncodeToString(b)
|
||||
|
||||
passwordretrieval := map[string]any{
|
||||
"username": email,
|
||||
"account_id": account.Account.Id,
|
||||
"key": key,
|
||||
}
|
||||
|
||||
h.cache.PutWithTTL("retrieve-password/"+key, passwordretrieval, 72*time.Hour)
|
||||
|
||||
if err := h.emailing.Send("auth.retrieve_password", email, passwordretrieval); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &LostPasswordInitResult{Success: true}, nil
|
||||
}
|
||||
|
||||
type LostPasswordRecoverResult struct {
|
||||
Success bool
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) RecoverLostPassword(key, newPassword string) (*LostPasswordRecoverResult, error) {
|
||||
recover, err := h.cache.Get("retrieve-password/" + key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if newPassword == "" {
|
||||
return nil, errors.New("password is empty")
|
||||
}
|
||||
|
||||
_, err = h.services.GRPC.MobilityAccounts.ChangePassword(context.TODO(), &mobilityaccounts.ChangePasswordRequest{
|
||||
Id: recover.(map[string]any)["account_id"].(string),
|
||||
Password: newPassword,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = h.cache.Delete("retrieve-password/" + key)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to delete password recovery key")
|
||||
}
|
||||
|
||||
return &LostPasswordRecoverResult{Success: true}, nil
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) GetPasswordRecoveryData(key string) (map[string]any, error) {
|
||||
recover, err := h.cache.Get("retrieve-password/" + key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return recover.(map[string]any), nil
|
||||
}
|
||||
|
||||
type OnboardingResult struct {
|
||||
Success bool
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) CompleteOnboarding(key, password, firstName, lastName string) (*OnboardingResult, error) {
|
||||
onboarding, err := h.cache.Get("onboarding/" + key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
onboardingmap := onboarding.(map[string]any)
|
||||
|
||||
if password == "" {
|
||||
return nil, errors.New("password is empty")
|
||||
}
|
||||
|
||||
groups := []string{
|
||||
onboardingmap["group"].(string),
|
||||
}
|
||||
|
||||
if onboardingmap["admin"].(bool) {
|
||||
groups = append(groups, onboardingmap["group"].(string)+":admin")
|
||||
}
|
||||
|
||||
display_name := firstName + " " + lastName
|
||||
account := &ma.Account{
|
||||
Authentication: ma.AccountAuth{
|
||||
Local: ma.LocalAuth{
|
||||
Username: onboardingmap["username"].(string),
|
||||
Password: password,
|
||||
},
|
||||
},
|
||||
Namespace: "parcoursmob",
|
||||
Data: map[string]any{
|
||||
"display_name": display_name,
|
||||
"first_name": firstName,
|
||||
"last_name": lastName,
|
||||
"email": onboardingmap["username"],
|
||||
"groups": groups,
|
||||
},
|
||||
}
|
||||
|
||||
acc, err := mobilityaccounts.AccountFromStorageType(account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request := &mobilityaccounts.RegisterRequest{
|
||||
Account: acc,
|
||||
}
|
||||
|
||||
_, err = h.services.GRPC.MobilityAccounts.Register(context.TODO(), request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = h.cache.Delete("onboarding/" + key)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to delete onboarding key")
|
||||
}
|
||||
|
||||
return &OnboardingResult{Success: true}, nil
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) GetOnboardingData(key string) (map[string]any, error) {
|
||||
onboarding, err := h.cache.Get("onboarding/" + key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return onboarding.(map[string]any), nil
|
||||
}
|
||||
|
||||
type UserGroupsResult struct {
|
||||
Groups []groupsstorage.Group
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) GetUserGroups(idtoken *oidc.IDToken) (*UserGroupsResult, error) {
|
||||
var claims map[string]any
|
||||
err := idtoken.Claims(&claims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
g := claims["groups"]
|
||||
groups_interface, ok := g.([]any)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid groups format")
|
||||
}
|
||||
|
||||
groups := []string{}
|
||||
for _, v := range groups_interface {
|
||||
groups = append(groups, v.(string))
|
||||
}
|
||||
|
||||
request := &grpcapi.GetGroupsBatchRequest{
|
||||
Groupids: groups,
|
||||
}
|
||||
|
||||
resp, err := h.services.GRPC.GroupsManagement.GetGroupsBatch(context.TODO(), request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var groupsresponse []groupsstorage.Group
|
||||
for _, group := range resp.Groups {
|
||||
if group.Namespace != "parcoursmob_organizations" {
|
||||
continue
|
||||
}
|
||||
g := group.ToStorageType()
|
||||
groupsresponse = append(groupsresponse, g)
|
||||
}
|
||||
|
||||
return &UserGroupsResult{Groups: groupsresponse}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user