173 lines
4.4 KiB
Go
173 lines
4.4 KiB
Go
package commandEmailPassToOidc
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
c "scripts/internal/config"
|
|
l "scripts/pkg/logger"
|
|
"scripts/pkg/postgres"
|
|
)
|
|
|
|
const Name = "usersUpdateLoginMethod"
|
|
|
|
func UsersUpdateLoginMethod() error {
|
|
if err := postgres.InitDB(); err != nil {
|
|
l.Log.Error().Err(err).Msg("failed to init postgres")
|
|
return err
|
|
}
|
|
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) {
|
|
const path = "/realms/master/protocol/openid-connect/token"
|
|
|
|
endpoint, err := url.Parse(c.Conf.KeycloakSettings.Address)
|
|
if err != nil {
|
|
l.Log.Error().Err(err).Msg("failed to create url")
|
|
return nil, err
|
|
}
|
|
endpoint.Path = path
|
|
|
|
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", endpoint.String(), &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) {
|
|
var path = fmt.Sprintf("/admin/realms/%s/users", c.Conf.KeycloakSettings.RealmName)
|
|
|
|
endpoint, err := url.Parse(c.Conf.KeycloakSettings.Address)
|
|
if err != nil {
|
|
l.Log.Error().Err(err).Msg("failed to create url")
|
|
return nil, err
|
|
}
|
|
endpoint.Path = path
|
|
|
|
req, err := http.NewRequest("GET", endpoint.String(), 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
|
|
}
|