Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
ElaadF committed Jun 24, 2021
1 parent 18e3b03 commit 1c4ca09
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 34 deletions.
4 changes: 4 additions & 0 deletions user-management/src/main/elm/sources/DataTypes.elm
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type alias User =

type alias UsersConf =
{ digest : String
, authenticationBackends: List String
, users : List User
}

Expand Down Expand Up @@ -63,6 +64,8 @@ type alias Model =
, hashedPasswd : Bool
, isValidInput : StateInput
, authzToAddOnSave : List String
, providers : List String
, shouldAskPassword : Bool
}

type Msg
Expand All @@ -85,6 +88,7 @@ type Msg
| SubmitUpdatedInfos User
| SubmitNewUser User
| PreHashedPasswd
| CheckExtAuth Bool

-- NOTIFICATIONS
| ToastyMsg (Toasty.Msg Toasty.Defaults.Toast)
Expand Down
2 changes: 1 addition & 1 deletion user-management/src/main/elm/sources/Init.elm
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ authorizations =
init : { contextPath : String } -> ( Model, Cmd Msg )
init flags =
let
initModel = Model flags.contextPath "" (fromList []) (fromList []) [] authorizations Toasty.initialState Closed "" "" True ValidInputs []
initModel = Model flags.contextPath "" (fromList []) (fromList []) [] authorizations Toasty.initialState Closed "" "" True ValidInputs [] [] True
in
( initModel
, getUsersConf initModel
Expand Down
2 changes: 2 additions & 0 deletions user-management/src/main/elm/sources/JsonDecoder.elm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ decodeCurrentUsersConf : Decoder UsersConf
decodeCurrentUsersConf =
D.succeed UsersConf
|> required "digest" D.string
|> required "authenticationBackends" (D.list <| D.string)
|> required "users" (D.list <| decodeUser)

decodeUser : Decoder User
Expand All @@ -30,6 +31,7 @@ decodeUser =
|> required "login" D.string
|> required "authz" (D.list <| D.string)
|> required "role" (D.list <| D.string)
--|> required "hasValidHash" D.bool

decodeApiRoleCoverage : Decoder Authorization
decodeApiRoleCoverage =
Expand Down
48 changes: 45 additions & 3 deletions user-management/src/main/elm/sources/UserManagement.elm
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import DataTypes exposing (Authorization, Model, Msg(..), PanelMode(..), StateIn
import Dict exposing (fromList)
import Http exposing (..)
import Init exposing (createErrorNotification, createSuccessNotification, defaultConfig, init, subscriptions)
import List exposing (all, filter)
import List exposing (all, filter, head)
import String exposing (isEmpty)
import Toasty
import View exposing (view)
Expand All @@ -27,6 +27,11 @@ getUser username users =
Nothing ->
Nothing

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


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Expand All @@ -37,10 +42,14 @@ update msg model =
case result of
Ok u ->
let
--isExtProviderExists =
-- case u.authenticationBackends of
-- Just p -> p
-- Nothing ->
recordUser =
List.map (\x -> (x.login, (Authorization x.authz x.role))) u.users
newModel =
{ model | users = fromList recordUser, digest = u.digest}
{ model | users = fromList recordUser, digest = u.digest, providers = u.authenticationBackends}

in
( newModel, getRoleConf model )
Expand Down Expand Up @@ -153,9 +162,26 @@ update msg model =
"" -- This case shouldn't happen since we must be in EditMod, it will invalidate the user in the file.
else
model.login
newPassword =
if model.shouldAskPassword then
case (takeFirstExtProvider model.providers) of
Just p -> p
Nothing -> ""
else
model.password
in
({model | authzToAddOnSave = [], password = "", login = "", panelMode = Closed}, updateUser model u.login model.password { u | login = model.login})
({model | authzToAddOnSave = [], password = "", login = "", panelMode = Closed}, updateUser model u.login newPassword { u | login = model.login})
SubmitNewUser u ->
--let
-- extProviders = filter (\p -> p /= "rootAdmin" || p /= "file") model.providers
-- newModel =
-- if (model.isRadioExtAuthOn) then
-- case (head extProviders) of
-- Just p -> ({model | password = p, hashedPasswd = True})
-- Nothing -> model
-- else
-- model
--in
if (isEmpty u.login && isEmpty model.password) then
({model | isValidInput = InvalidInputs}, Cmd.none)
else if (isEmpty u.login) then
Expand All @@ -170,6 +196,22 @@ update msg model =
({model | password = "",hashedPasswd = False}, Cmd.none)
else
({model | password = "", hashedPasswd = True}, Cmd.none)
CheckExtAuth isChecked ->
let
extProvider =
case (takeFirstExtProvider model.providers) of
Just p -> p
Nothing -> ""
in
if isChecked then
({model | password = extProvider, shouldAskPassword = False}, Cmd.none)
else
if (isEmpty extProvider) then
({model | shouldAskPassword = True}, Cmd.none)
else
({model | shouldAskPassword = False}, Cmd.none)



processApiError : Error -> Model -> ( Model, Cmd Msg )
processApiError err model =
Expand Down
38 changes: 29 additions & 9 deletions user-management/src/main/elm/sources/View.elm
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ module View exposing (..)
import ApiCalls exposing (deleteUser)

import DataTypes exposing (PanelMode(..), Model, Msg(..), RoleConf, Roles, StateInput(..), User, Username, Users, UsersConf)
import Debug exposing (log)
import Dict exposing (keys)
import Html exposing (Html, a, br, button, div, h2, h3, h4, h5, i, input, p, span, text)
import Html.Attributes exposing (attribute, class, disabled, href, id, placeholder, required, type_, value)
import Html.Events exposing (onClick, onInput)
import Html exposing (Html, a, br, button, div, h2, h3, h4, h5, i, input, label, p, span, text)
import Html.Attributes exposing (attribute, checked, class, disabled, for, href, id, name, placeholder, required, type_, value)
import Html.Events exposing (onCheck, onClick, onInput)
import Init exposing (defaultConfig)
import List exposing (all, any, filter, map)
import String exposing (isEmpty)
Expand All @@ -37,17 +38,18 @@ hashPasswordMenu : Model -> Html Msg
hashPasswordMenu model =
let
hashPasswdIsActivate =
if (model.hashedPasswd == True) then
"active"
if (model.hashedPasswd == True && model.shouldAskPassword) then
"active "
else
""
clearPasswdIsActivate =
if (model.hashedPasswd == False) then
"active"
if (model.hashedPasswd == False && model.shouldAskPassword) then
"active "
else
""
isDeactivate = if model.shouldAskPassword then "" else "btn-group-deactivate "
in
div [class "btn-group", attribute "role" "group"]
div [class ("btn-group " ++ isDeactivate), attribute "role" "group"]
[
a [class ("btn btn-default " ++ hashPasswdIsActivate), onClick PreHashedPasswd][text "Enter pre-hashed value"]
, a [class ("btn btn-default " ++ clearPasswdIsActivate), onClick PreHashedPasswd][text "Password to hash"]
Expand All @@ -71,13 +73,16 @@ displayRightPanelAddUser model =
if (model.isValidInput == InvalidPassword || model.isValidInput == InvalidInputs) then "invalid-password" else "valid-input"
_ ->
"valid-input"
externalProviders = filter (\p -> (p /= "file" && p /= "rootAdmin")) model.providers

in
div [class "panel-wrap"]
[
div [class "panel"]
[
button [class "btn btn-sm btn-outline-secondary", onClick DeactivatePanel][text "Close"]
, div[class "card-header"][h2 [class "title-username"] [text "Create User"]]
, displayCheckBoxExtAuth (log "providersFIlter" externalProviders)
, div []
[
input [id emptyUsername, class "form-control username-input", type_ "text", placeholder "Username", onInput Login, required True] []
Expand All @@ -102,6 +107,17 @@ displayDropdownRoleList roles =
in
div [class "dropdown-content"] tokens

displayCheckBoxExtAuth : List String -> Html Msg
displayCheckBoxExtAuth extProviders =
let
isDisabled = List.isEmpty extProviders
classMsgColor = if isDisabled then "disable-msg-auth" else "enable-msg-auth"
in
div [class "ext-auth-wrapper"]
[
input [type_ "checkbox", id "extAuthEnabled", disabled isDisabled, onCheck (\checkstatus -> CheckExtAuth checkstatus)][]
, label [for "extAuthEnabled", class ("label-msg-ext-auth " ++ classMsgColor)][text "Use external authentication for this user"]
]

displayRightPanel : Model -> Html Msg
displayRightPanel model =
Expand All @@ -116,6 +132,9 @@ displayRightPanel model =
else
button [class "addBtn"][i [class "fa fa-plus"][]]
isHidden = if model.hashedPasswd then "text" else "password"
externalProviders = filter (\p -> (p /= "file" && p /= "rootAdmin")) model.providers
classDeactivatePasswdInput = if (log "input pass " model.shouldAskPassword) then "" else " input-passwd-deactivate "

in
div [class "panel-wrap"]
[
Expand All @@ -126,9 +145,10 @@ displayRightPanel model =
h2 [class "title-username"] [text user.login]
, button [class "btn btn-sm btn-outline-secondary", onClick DeactivatePanel][text "Close"]
]
, displayCheckBoxExtAuth (log "providersFIlter" externalProviders)
, input [class "form-control username-input", type_ "text", placeholder "New Username", onInput Login] []
, hashPasswordMenu model
, input [class "form-control", type_ isHidden, placeholder "New Password", onInput Password, attribute "autocomplete" "new-password", value model.password ] []
, input [class ("form-control " ++ classDeactivatePasswdInput), type_ isHidden, placeholder "New Password", onInput Password, attribute "autocomplete" "new-password", value model.password] []
, h4 [class "role-title"][text "Roles"]
, div [class "role-management-wrapper"]
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,33 @@ h3 {
color : #f08004;
}

.ext-auth-wrapper {
margin-top : 20px;
margin-bottom : 40px;
white-space: nowrap;
}

.label-msg-ext-auth {
font-weight: normal;
margin-left : 10px;
}

.disable-msg-auth {
color: #bbbbbb;
}

.enable-msg-auth {
color: black;
}

.btn-group-deactivate {
cursor: not-allowed;
opacity: 0.4;
background: #CCC;
}

.input-passwd-deactivate {
cursor: not-allowed;
opacity: 0.4;
background: #CCC;
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
package com.normation.plugins.usermanagement

import bootstrap.liftweb.PasswordEncoder
import bootstrap.liftweb.RudderConfig
import bootstrap.liftweb.UserDetailList
import com.normation.rudder.Role
import com.normation.rudder.Role.Custom
Expand All @@ -53,19 +54,13 @@ object UserManagementLogger extends Logger {
override protected def _logger = LoggerFactory.getLogger("usermanagement")
}


object Serialisation {

implicit class AuthConfigSer(auth: UserDetailList) {
def toJson: JValue = {
val encoder = auth.encoder match {
case PasswordEncoder.MD5 => "MD5"
case PasswordEncoder.SHA1 => "SHA-1"
case PasswordEncoder.SHA256 => "SHA-256"
case PasswordEncoder.SHA512 => "SHA-512"
case PasswordEncoder.BCRYPT => "BCRYPT"
case _ => "plain text"
}
val encoder: String = PassEncoderToString(auth)
val authBackendsProvider = RudderConfig.authenticationProviders.getConfiguredProviders.map(_.name).toSet


val jUser = auth.users.map {
case(_,u) =>
Expand All @@ -74,26 +69,40 @@ object Serialisation {
case _ => true
}
JsonUser(
u.getUsername
, if (custom.isEmpty) Set.empty else custom.head.rights.displayAuthorizations.split(",").toSet
u.getUsername
, if (custom.isEmpty) Set.empty else custom.head.rights.displayAuthorizations.split(",").toSet
, rs.map(_.name)
, UserOrigin.verifyHash(encoder, u.getPassword)
)
}.toList.sortBy( _.login )
val json = JsonAuthConfig(encoder, jUser)
val json = JsonAuthConfig(encoder, authBackendsProvider, jUser)
import net.liftweb.json._
implicit val formats = S.formats(NoTypeHints)
Extraction.decompose(json)
}
}

def PassEncoderToString(auth: UserDetailList): String = {
auth.encoder match {
case PasswordEncoder.MD5 => "MD5"
case PasswordEncoder.SHA1 => "SHA-1"
case PasswordEncoder.SHA256 => "SHA-256"
case PasswordEncoder.SHA512 => "SHA-512"
case PasswordEncoder.BCRYPT => "BCRYPT"
case _ => "plain text"
}
}
}

final case class JsonAuthConfig(
digest: String
, authenticationBackends: Set[String]
, users : List[JsonUser]
)

final case class JsonUser(
login: String
, authz: Set[String]
, role: Set[String]
, hasValidHash: Boolean
)
Loading

0 comments on commit 1c4ca09

Please sign in to comment.