package commandEmailPassToOidc import ( "bytes" "encoding/json" "fmt" "net/http" c "scripts/internal/config" l "scripts/pkg/logger" "scripts/pkg/postgres" ) const Name = "usersUpdateLoginMethod" func UsersUpdateLoginMethod() error { postgres.InitDB() defer postgres.DB.Close() tokenData, err := keycloakAccessToken() if err != nil { l.Log.Error().Err(err).Msg("failed to get access token from keycloak") return err } loopUsers, err := allLoopUsers() if err != nil { l.Log.Error().Err(err).Msg("failed to get users from loop db") return err } if len(loopUsers) == 0 { l.Log.Info().Msg("no users in loop db for change login") return nil } keycloakUsers, err := allKeycloakUsers(tokenData.AccessToken) if err != nil { l.Log.Error().Err(err).Msg("failed to get users from kecloak") return err } if err := changeLogin(loopUsers, keycloakUsers); err != nil { return err } l.Log.Info().Str("name", Name).Msg("command successfully") return nil } func keycloakAccessToken() (*KeycloakTokenResponse, error) { url := fmt.Sprintf("%s/realms/%s/protocol/openid-connect/token", c.Conf.KeycloakSettings.Address, "master") var data bytes.Buffer fmt.Fprintf(&data, "grant_type=password&client_id=admin-cli&username=%s&password=%s", c.Conf.KeycloakSettings.AdminName, c.Conf.KeycloakSettings.AdminPass) req, err := http.NewRequest("POST", url, &data) if err != nil { l.Log.Error().Err(err).Msg("failed to create http request") return nil, err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") client := http.Client{} resp, err := client.Do(req) if err != nil { l.Log.Error().Err(err).Msg("failed to exec http request") return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("failed to get access token, status %d", resp.StatusCode) } var tokenResp KeycloakTokenResponse if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { l.Log.Error().Err(err).Msg("failed to decode body response") return nil, err } return &tokenResp, nil } func allLoopUsers() (map[string]LoopUser, error) { ctx := postgres.DB.Context() var users []LoopUser if err := postgres.DB.Conn().SelectContext(ctx, &users, allUsersQuery); err != nil { l.Log.Error().Err(err).Msg("failed to select query") return nil, err } result := make(map[string]LoopUser, len(users)) for _, el := range users { result[el.Email] = el } return result, nil } func allKeycloakUsers(accessToken string) ([]KeycloakUser, error) { url := fmt.Sprintf("%s/admin/realms/%s/users", c.Conf.KeycloakSettings.Address, c.Conf.KeycloakSettings.RealmName) req, err := http.NewRequest("GET", url, nil) if err != nil { l.Log.Error().Err(err).Msg("failed to create http request") return nil, err } req.Header.Set("Authorization", "Bearer "+accessToken) client := http.Client{} resp, err := client.Do(req) if err != nil { l.Log.Error().Err(err).Msg("failed to exec http request") return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("failed to get users: status %d", resp.StatusCode) } var users []KeycloakUser if err := json.NewDecoder(resp.Body).Decode(&users); err != nil { l.Log.Error().Err(err).Msg("failed to decode body response") return nil, err } return users, nil } func changeLogin(loopUsers map[string]LoopUser, keycloakUsers []KeycloakUser) error { for _, el := range keycloakUsers { user, exists := loopUsers[el.Email] if !exists { l.Log.Warn().Str("email", el.Email).Msg("user not found") continue } // NOTE: если в keycloak не были указаны firstname и lastname - при первои входе сам keycloak спросит их и ЗАМЕНИТ данные в БД loop if _, err := postgres.DB.Conn().ExecContext(postgres.DB.Context(), changeLoginQuery, user.Id, el.ID, el.EmailVerified); err != nil { l.Log.Error().Err(err).Msg("failed to exec update query") return err } l.Log.Info().Str("email", el.Email).Msg("successfully update") } return nil }