Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
clarktsiory committed Feb 23, 2024
1 parent f71a9ea commit 4c91459
Show file tree
Hide file tree
Showing 16 changed files with 1,085 additions and 476 deletions.
84 changes: 76 additions & 8 deletions user-management/src/main/elm/sources/DataTypes.elm
Expand Up @@ -8,12 +8,14 @@ import Toasty.Defaults

type alias Roles = Dict String (List String)
type alias Users = Dict Username User
type alias Provider = String
type alias Username = String
type alias Password = String
type alias RoleConf = List Role
type alias ProvidersInfo = Dict Provider ProviderInfo

type alias AddUserForm =
{ user : User
{ user : NewUser
, password : String
, isPreHashed : Bool
}
Expand All @@ -25,18 +27,39 @@ type alias Role =

type alias User =
{ login : String
, status : UserStatus
, authz : List String
, roles : List String
, rolesCoverage : List String
, customRights : List String
, providers : List String
, providersInfo : ProvidersInfo
}

type UserStatus =
Active
| Disabled
| Deleted

-- Payload to create a new user or update an existing one
type alias NewUser =
{ login : String
, authz : List String
, roles : List String
}

type alias ProviderProperties =
{ roleListOverride : RoleListOverride
, hasModifiablePassword : Bool
}

type alias ProviderInfo =
{ provider : String
, authz : List String
, roles : List String
, customRights : List String
}

-- does the configured list of provider allows to change the list of user roles, and how (extend only, or override?)
-- Note: until rudder core is updated to give us the info, we can only guess based on provider list
type RoleListOverride
Expand All @@ -51,17 +74,61 @@ userProviders: List String -> List String
userProviders providers =
List.filter (\p -> p /= "rootAdmin") providers

takeFirstExtProvider: List String -> Maybe String
takeFirstExtProvider providers =
List.head (List.filter (\p -> p /= "file" && p /= "rootAdmin") providers)
filterExternalProviders: List String -> List String
filterExternalProviders providers =
List.filter (\p -> p /= "file" && p /= "rootAdmin") providers

filterUserProviderByRoleListOverride: RoleListOverride -> Model -> User -> List ProviderInfo
filterUserProviderByRoleListOverride value model user =
user.providers
|> filterExternalProviders
|> List.filter (\p ->
Dict.get p model.providersProperties
|> Maybe.map (\pp -> pp.roleListOverride == value)
|> Maybe.withDefault False
)
|> List.filterMap (\p ->
Dict.get p user.providersInfo
)

getFileProviderInfo: User -> Maybe ProviderInfo
getFileProviderInfo user =
Dict.get "file" user.providersInfo

newUserToUser : NewUser -> User
newUserToUser {login, authz, roles} = {login = login, authz = authz, roles = roles, rolesCoverage = [], customRights = []}
takeFirstExtProvider: List String -> Maybe String
takeFirstExtProvider = List.head << filterExternalProviders

takeFirstOverrideProviderInfo : Model -> User -> Maybe ProviderInfo
takeFirstOverrideProviderInfo model user =
filterUserProviderByRoleListOverride Override model user
|> List.head

takeFirstExtendProviderInfo : Model -> User -> Maybe ProviderInfo
takeFirstExtendProviderInfo model user =
filterUserProviderByRoleListOverride Extend model user
|> List.head

providerHasModifiablePassword : Model -> Provider -> Bool
providerHasModifiablePassword model provider =
provider == "file" || (
Dict.get provider model.providersProperties
|> Maybe.map .hasModifiablePassword
|> Maybe.withDefault False
)

providerCanEditRoles : Model -> Provider -> Bool
providerCanEditRoles model provider =
provider == "file" || (
Dict.get provider model.providersProperties
|> Maybe.map (\p -> p.roleListOverride /= Override)
|> Maybe.withDefault False
)

type alias UsersConf =
{ digest : String
, roleListOverride: RoleListOverride
, authenticationBackends: List String
, providersProperties : Dict String ProviderProperties
, users : List User
}

Expand Down Expand Up @@ -89,6 +156,7 @@ type alias Model =
, isValidInput : StateInput
, rolesToAddOnSave : List String
, providers : List String
, providersProperties: Dict String ProviderProperties
, userForcePasswdInput : Bool
, openDeleteModal : Bool
}
Expand All @@ -108,8 +176,8 @@ type Msg
| Password String
| Login String
| AddRole String
| RemoveRole User String
| SubmitUpdatedInfos User
| RemoveRole User Provider String
| SubmitUpdatedInfos NewUser
| SubmitNewUser NewUser
| PreHashedPasswd Bool
| AddPasswdAnyway
Expand Down
2 changes: 1 addition & 1 deletion user-management/src/main/elm/sources/Init.elm
Expand Up @@ -15,7 +15,7 @@ subscriptions model =
init : { contextPath : String } -> ( Model, Cmd Msg )
init flags =
let
initModel = Model flags.contextPath "" (fromList []) (fromList []) [] None Toasty.initialState Closed "" "" True ValidInputs [] [] False False
initModel = Model flags.contextPath "" (fromList []) (fromList []) [] None Toasty.initialState Closed "" "" True ValidInputs [] [] Dict.empty False False
in
( initModel
, getUsersConf initModel
Expand Down
37 changes: 36 additions & 1 deletion user-management/src/main/elm/sources/JsonDecoder.elm
@@ -1,8 +1,11 @@
module JsonDecoder exposing (..)

import DataTypes exposing (Role, RoleConf, RoleListOverride(..), User, UsersConf)
import DataTypes exposing (Role, RoleConf, RoleListOverride(..), User, UserStatus(..), UsersConf)
import Json.Decode as D exposing (Decoder)
import Json.Decode.Pipeline exposing (required)
import DataTypes exposing (ProviderInfo)
import DataTypes exposing (ProvidersInfo)
import DataTypes exposing (ProviderProperties)

decodeApiReloadResult : Decoder String
decodeApiReloadResult =
Expand All @@ -24,8 +27,15 @@ decodeCurrentUsersConf =
|> required "digest" D.string
|> required "roleListOverride" decodeRoleListOverride
|> required "authenticationBackends" (D.list <| D.string)
|> required "providerProperties" (D.dict decodeProviderProperties)
|> required "users" (D.list <| decodeUser)

decodeProviderProperties : Decoder ProviderProperties
decodeProviderProperties =
D.succeed ProviderProperties
|> required "roleListOverride" decodeRoleListOverride
|> required "hasModifiablePassword" D.bool

decodeRoleListOverride : Decoder RoleListOverride
decodeRoleListOverride =
D.string |> D.andThen
Expand All @@ -36,15 +46,40 @@ decodeRoleListOverride =
_ -> D.succeed None
)

decodeProviderInfo : Decoder ProviderInfo
decodeProviderInfo =
D.succeed ProviderInfo
|> required "provider" D.string
|> required "authz" (D.list <| D.string)
|> required "roles" (D.list <| D.string)
|> required "customRights" (D.list <| D.string)

-- Decode dict of providers info, the key is the provider
decodeProvidersInfo : Decoder ProvidersInfo
decodeProvidersInfo =
D.dict decodeProviderInfo

decodeUser : Decoder User
decodeUser =
D.succeed User
|> required "login" D.string
|> required "status" decodeUserStatus
|> required "authz" (D.list <| D.string)
|> required "permissions" (D.list <| D.string)
|> required "rolesCoverage" (D.list <| D.string)
|> required "customRights" (D.list <| D.string)
|> required "providers" (D.list <| D.string)
|> required "providersInfo" decodeProvidersInfo

decodeUserStatus : Decoder UserStatus
decodeUserStatus =
D.string |> D.andThen
(\str ->
case str of
"active" -> D.succeed Active
"disabled" -> D.succeed Disabled
_ -> D.succeed Deleted
)

decodeApiAddUserResult : Decoder String
decodeApiAddUserResult =
Expand Down
17 changes: 9 additions & 8 deletions user-management/src/main/elm/sources/UserManagement.elm
Expand Up @@ -2,7 +2,7 @@ module UserManagement exposing (processApiError, update)

import ApiCalls exposing (addUser, getRoleConf, getUsersConf, postReloadConf, updateUser)
import Browser
import DataTypes exposing (Model, Msg(..), PanelMode(..), StateInput(..), newUserToUser, userProviders)
import DataTypes exposing (Model, Msg(..), PanelMode(..), StateInput(..), userProviders)
import Dict exposing (fromList)
import Http exposing (..)
import Init exposing (createErrorNotification, createSuccessNotification, defaultConfig, init, subscriptions)
Expand Down Expand Up @@ -44,7 +44,7 @@ update msg model =
_ ->
Closed
newModel =
{ model | roleListOverride = u.roleListOverride, users = users, panelMode = newPanelMode, digest = u.digest, providers = (userProviders u.authenticationBackends)}
{ model | roleListOverride = u.roleListOverride, users = users, panelMode = newPanelMode, digest = u.digest, providers = (userProviders u.authenticationBackends), providersProperties = u.providersProperties}

in
( newModel, getRoleConf model )
Expand Down Expand Up @@ -125,10 +125,10 @@ update msg model =

AddRole r ->
({model | rolesToAddOnSave = r :: model.rolesToAddOnSave}, Cmd.none)
RemoveRole user r ->
RemoveRole user provider r ->
let
-- remove role, and also authz that are associated to the role but not associated with any other remaining role
newRoles = user.roles |> List.filter (\x -> r /= x)
newRoles = Dict.get provider user.providersInfo |> Maybe.map .roles |> Maybe.withDefault [] |> List.filter (\x -> r /= x)
newAuthz =
-- keep authz if it is found in any authz of newRoles
-- keep authz if it's in custom authz of the user
Expand All @@ -142,9 +142,10 @@ update msg model =
newRoles
|> List.any (\y -> List.member y allAuthz)
) user.authz
newUser = {user | roles = newRoles, authz = newAuthz}
newUser = {login = user.login, authz = newAuthz, roles = newRoles}
newPanelMode = EditMode {user | authz = newAuthz, roles = newRoles}
in
({model | panelMode = EditMode newUser}, updateUser model user.login (DataTypes.AddUserForm newUser "" model.isHashedPasswd))
({model | panelMode = newPanelMode}, updateUser model user.login (DataTypes.AddUserForm newUser "" model.isHashedPasswd))
Notification subMsg ->
Toasty.update defaultConfig Notification subMsg model

Expand All @@ -153,7 +154,7 @@ update msg model =
Login newLogin ->
({model | isValidInput = ValidInputs, login = newLogin}, Cmd.none)
SubmitUpdatedInfos u ->
({model | rolesToAddOnSave = [], password = "", userForcePasswdInput = False, login = ""}, updateUser model u.login (DataTypes.AddUserForm { u | login = u.login} model.password model.isHashedPasswd))
({model | rolesToAddOnSave = [], password = "", userForcePasswdInput = False, login = ""}, updateUser model u.login (DataTypes.AddUserForm u model.password model.isHashedPasswd))
SubmitNewUser u ->
if(isEmpty u.login) then
({model | isValidInput = InvalidUsername}, Cmd.none)
Expand All @@ -167,7 +168,7 @@ update msg model =
, isValidInput = ValidInputs
, rolesToAddOnSave = []
}
, addUser model (DataTypes.AddUserForm (newUserToUser u) model.password model.isHashedPasswd)
, addUser model (DataTypes.AddUserForm u model.password model.isHashedPasswd)
)

PreHashedPasswd bool ->
Expand Down

0 comments on commit 4c91459

Please sign in to comment.