diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/secrets/Secret.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/secrets/Secret.scala index 79c75d4e219..5c80584188d 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/secrets/Secret.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/secrets/Secret.scala @@ -39,13 +39,12 @@ package com.normation.rudder.domain.secrets import net.liftweb.json.JsonAST.JValue import net.liftweb.json.JsonDSL._ -final case class Secret(name: String, value: String) +final case class Secret(name: String, value: String, description: String) object Secret { - - def serializeSecret(secret : Secret): JValue = { - ( ("name" -> secret.name) - ~ ("value" -> secret.value) - ) + def serializeSecretInfo(secret : Secret): JValue = { + ( ("name" -> secret.name) + ~ ("description" -> secret.description) + ) } } diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/secrets/SecretDiff.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/secrets/SecretDiff.scala index 30ffd7cd61c..a541b4efb17 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/secrets/SecretDiff.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/secrets/SecretDiff.scala @@ -46,8 +46,9 @@ final case class AddSecretDiff(secret: Secret) extends SecretDiff final case class DeleteSecretDiff(secret: Secret) extends SecretDiff final case class ModifySecretDiff( - name : String - , value : String - , modValue : Option[SimpleDiff[String]] = None + name : String + , description : String + , modValue : Boolean + , modDescription : Option[SimpleDiff[String]] = None ) extends SecretDiff diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/repository/jdbc/EventLogJdbcRepository.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/repository/jdbc/EventLogJdbcRepository.scala index 9d7e76698fd..6bd6e7c3b52 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/repository/jdbc/EventLogJdbcRepository.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/repository/jdbc/EventLogJdbcRepository.scala @@ -114,7 +114,6 @@ class EventLogJdbcRepository( ) match { case Right(log) => log case Left(error) => - println(error) logEffect.warn(s"Error when trying to get the event type, recorded type was: '${eventType}'") UnspecializedEventLog(eventLogDetails) } diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/eventlog/EventLogDetailsService.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/eventlog/EventLogDetailsService.scala index 17c98de934b..1384d8b195c 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/eventlog/EventLogDetailsService.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/eventlog/EventLogDetailsService.scala @@ -855,15 +855,17 @@ class EventLogDetailsServiceImpl( (s"Entry type is not a Secret: ${entry}") name <- (secret \ "name").headOption.map( _.text ) ?~! (s"Missing attribute 'name' in entry type Secret: ${entry}") - value <- (secret \ "value").headOption.map( _.text ) ?~! - (s"Missing attribute 'value' in entry type Secret: ${entry}") - modValue <- getFromToString((secret \ "diffValue").headOption) + description <- (secret \ "description").headOption.map( _.text ) ?~! + (s"Missing attribute 'description' in entry type Secret: ${entry}") + modValue <- tryo{(secret \ "valueHasChanged").text.toBoolean} + modDescription <- getFromToString((secret \ "diffDescription").headOption) fileFormatOk <- TestFileFormat(secret) } yield { ModifySecretDiff( name = name - , value = value + , description = description , modValue = (modValue) + , modDescription = (modDescription) ) } } diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/eventlog/EventLogFactory.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/eventlog/EventLogFactory.scala index 8106c1ea06e..75099d0b3ee 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/eventlog/EventLogFactory.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/eventlog/EventLogFactory.scala @@ -768,7 +768,7 @@ class EventLogFactoryImpl( ) : AddSecret = { val details = EventLog.withContent(secretXmlSerializer.serialise(secret) % ("changeType" -> "add")) AddSecret(EventLogDetails( - id = id + id = id , modificationId = modificationId , principal = principal , details = details @@ -789,7 +789,7 @@ class EventLogFactoryImpl( val details = EventLog.withContent(secretXmlSerializer.serialise(secret) % ("changeType" -> "delete")) DeleteSecret(EventLogDetails( - id = id + id = id , modificationId = modificationId , principal = principal , details = details @@ -809,13 +809,25 @@ class EventLogFactoryImpl( , reason : Option[String] ) : ModifySecret = { - val diffValue = SimpleDiff.stringToXml(, SimpleDiff(oldSecret.value, newSecret.value) ) + val diffValue = { + if(oldSecret.value != newSecret.value) + True + else + False + } + + val diffDescription = { + if(oldSecret.description != newSecret.description) + Some(SimpleDiff.stringToXml(, SimpleDiff(oldSecret.description, newSecret.description) )) + else + None + } val details = EventLog.withContent{ scala.xml.Utility.trim( {oldSecret.name} - {oldSecret.value} - {diffValue} + {oldSecret.description} + {diffValue ++ diffDescription} ) } ModifySecret(EventLogDetails( diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlSerialisationImpl.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlSerialisationImpl.scala index 391a213df16..5512c6e2d68 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlSerialisationImpl.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlSerialisationImpl.scala @@ -292,7 +292,7 @@ class SecretSerialisationImpl(xmlVersion:String) extends SecretSerialisation { def serialise(secret:Secret): Elem = { createTrimedElem(XML_TAG_SECRET, xmlVersion) ( {secret.name} - {secret.value} + {secret.description} ) } } diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlUnserialisationImpl.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlUnserialisationImpl.scala index 093a621a2cd..4839eceb1f3 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlUnserialisationImpl.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlUnserialisationImpl.scala @@ -663,10 +663,11 @@ class SecretUnserialisationImpl extends SecretUnserialisation { } fileFormatOk <- TestFileFormat(secret) - name <- (secret \ "name").headOption.map( _.text ) ?~! ("Missing attribute 'name' in entry type globalParameter : " + entry) - value <- (secret \ "value").headOption.map( _.text ) ?~! ("Missing attribute 'value' in entry type globalParameter : " + entry) + name <- (secret \ "name").headOption.map( _.text ) ?~! ("Missing attribute 'name' in entry type secret : " + entry) +// value <- (secret \ "value").headOption.map( _.text ) ?~! ("Missing attribute 'value' in entry type secret : " + entry) + description <- (secret \ "description").headOption.map( _.text ) ?~! ("Missing attribute 'description' in entry type secret : " + entry) } yield { - Secret(name, value) + Secret(name, "", description) } } } diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/EndpointsDefinition.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/EndpointsDefinition.scala index 198568f1bc8..71fef8b5905 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/EndpointsDefinition.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/EndpointsDefinition.scala @@ -754,29 +754,34 @@ object UserApi extends ApiModuleProvider[UserApi] { } -sealed trait SecretVaultApi extends EndpointSchema with GeneralApi with SortIndex -object SecretVaultApi extends ApiModuleProvider[SecretVaultApi] { - final case object GetSecrets extends SecretVaultApi with ZeroParam with StartsAtVersion13 with SortIndex { val z = implicitly[Line].value - val description = "Get the list of key-value pair secret" +sealed trait SecretApi extends EndpointSchema with GeneralApi with SortIndex +object SecretApi extends ApiModuleProvider[SecretApi] { + final case object GetAllSecret extends SecretApi with ZeroParam with StartsAtVersion13 with SortIndex { val z = implicitly[Line].value + val description = "Get the list of key-value pair secret" val (action, path) = GET / "secret" } - final case object AddSecret extends SecretVaultApi with ZeroParam with StartsAtVersion13 with SortIndex { val z = implicitly[Line].value - val description = "Add a key-value pair secret" + final case object GetSecret extends SecretApi with OneParam with StartsAtVersion13 with SortIndex { val z = implicitly[Line].value + val description = "Get one key-value pair secret" + val (action, path) = GET / "secret" / "{id}" + } + + final case object AddSecret extends SecretApi with ZeroParam with StartsAtVersion13 with SortIndex { val z = implicitly[Line].value + val description = "Add a key-value pair secret" val (action, path) = PUT / "secret" } - final case object UpdateSecret extends SecretVaultApi with ZeroParam with StartsAtVersion13 with SortIndex { val z = implicitly[Line].value - val description = "Update an existing key-value pair secret" + final case object UpdateSecret extends SecretApi with ZeroParam with StartsAtVersion13 with SortIndex { val z = implicitly[Line].value + val description = "Update an existing key-value pair secret" val (action, path) = POST / "secret" } - final case object DeleteSecret extends SecretVaultApi with OneParam with StartsAtVersion13 with SortIndex { val z = implicitly[Line].value - val description = "Delete a secret" + final case object DeleteSecret extends SecretApi with OneParam with StartsAtVersion13 with SortIndex { val z = implicitly[Line].value + val description = "Delete a secret" val (action, path) = DELETE / "secret" / "{id}" } - def endpoints = ca.mrvisser.sealerate.values[SecretVaultApi].toList.sortBy( _.z ) + def endpoints = ca.mrvisser.sealerate.values[SecretApi].toList.sortBy( _.z ) } @@ -797,7 +802,7 @@ object AllApi { RuleApi.endpoints ::: InventoryApi.endpoints ::: InfoApi.endpoints ::: - SecretVaultApi.endpoints ::: + SecretApi.endpoints ::: // UserApi is not declared here, it will be contributed by plugin Nil } diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RestExtractorService.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RestExtractorService.scala index b791b781295..76edb8c144d 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RestExtractorService.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RestExtractorService.scala @@ -1315,10 +1315,12 @@ final case class RestExtractorService ( for { name <- extractJsonString(json,"name") value <- extractJsonString(json, "value") - s <- (name, value) match { - case (None, v) => Failure(s"Missing name parameter for secret entry when parsing request") - case (n, None) => Failure(s"Missing value parameter for secret entry when parsing request") - case (Some(n), Some(v)) => Full(Secret(n,v)) + description <- extractJsonString(json, "description") + s <- (name, value, description) match { + case (None, v, d) => Failure(s"Missing `name` parameter for secret entry when parsing request") + case (n, None, d) => Failure(s"Missing `value` parameter for secret entry when parsing request") + case (n, v, None) => Failure(s"Missing `description` parameter for secret entry when parsing request") + case (Some(n), Some(v), Some(d)) => Full(Secret(n,v,d)) } } yield s } diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RoleApiMapping.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RoleApiMapping.scala index ed4c52da808..4e8b22b1148 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RoleApiMapping.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RoleApiMapping.scala @@ -106,8 +106,8 @@ final case object OnlyAdmin extends AuthorizationApiMapping { SystemApi.ArchivesFullList.x :: SystemApi.ArchivesGroupsList.x :: SystemApi.ArchivesRulesList.x :: SystemApi.GetAllZipArchive.x :: SystemApi.GetDirectivesZipArchive.x :: SystemApi.GetGroupsZipArchive.x :: SystemApi.GetRulesZipArchive.x :: SystemApi.Info.x :: SystemApi.Status.x :: SystemApi.ArchivesParametersList.x :: - SystemApi.GetParametersZipArchive.x :: SystemApi.GetHealthcheckResult.x :: SecretVaultApi.GetSecrets.x :: - SecretVaultApi.AddSecret.x :: SecretVaultApi.DeleteSecret.x :: SecretVaultApi.UpdateSecret.x :: Nil + SystemApi.GetParametersZipArchive.x :: SystemApi.GetHealthcheckResult.x :: SecretApi.GetAllSecret.x :: + SecretApi.GetSecret.x :: SecretApi.AddSecret.x :: SecretApi.DeleteSecret.x :: SecretApi.UpdateSecret.x :: Nil case Administration.Write => SettingsApi.ModifySettings.x :: SettingsApi.ModifySetting.x :: SystemApi.endpoints.map(_.x) case Administration.Edit => SettingsApi.ModifySettings.x :: SettingsApi.ModifySetting.x :: SystemApi.endpoints.map(_.x) diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/lift/SecretApi.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/lift/SecretApi.scala index 8fc270ce2e7..5c8f774b6ea 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/lift/SecretApi.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/lift/SecretApi.scala @@ -37,19 +37,19 @@ package com.normation.rudder.rest.lift import com.normation.box._ +import com.normation.errors.IOResult import com.normation.rudder.domain.secrets.Secret import com.normation.rudder.rest.ApiPath import com.normation.rudder.rest.ApiVersion import com.normation.rudder.rest.AuthzToken import com.normation.rudder.rest.RestExtractorService import com.normation.rudder.rest.RestUtils -import com.normation.rudder.rest.{SecretVaultApi => API} +import com.normation.rudder.rest.{SecretApi => API} import com.normation.rudder.web.services.SecretService -import net.liftweb.common._ import net.liftweb.http.LiftResponse import net.liftweb.http.Req import net.liftweb.json.JArray -import net.liftweb.json.JsonDSL._ +import net.liftweb.json.JString class SecretApi( @@ -62,7 +62,8 @@ class SecretApi( def getLiftEndpoints(): List[LiftApiModule] = { API.endpoints.map( e => e match { - case API.GetSecrets => GetSecrets + case API.GetAllSecret => GetAllSecret + case API.GetSecret => GetSecret case API.AddSecret => AddSecret case API.UpdateSecret => UpdateSecret case API.DeleteSecret => DeleteSecret @@ -70,27 +71,39 @@ class SecretApi( ) } - object GetSecrets extends LiftApiModule0 { - val schema = API.GetSecrets + object GetAllSecret extends LiftApiModule0 { + val schema = API.GetAllSecret val restExtractor = restExtractorService def process0(version: ApiVersion, path: ApiPath, req: Req, params: DefaultParams, authzToken: AuthzToken): LiftResponse = { implicit val prettify = params.prettify - implicit val action = schema.name + implicit val action = schema.name val res = for { - secrets <- secretService.getSecrets + secrets <- secretService.getAllSecret.toBox } yield { - secrets.map(Secret.serializeSecret) + JArray(secrets.map(Secret.serializeSecretInfo)) } - res.toBox match { - case Full(json) => - RestUtils.toJsonResponse(None, JArray(json)) - case eb: EmptyBox => - val message = (eb ?~ s"Error when trying get secret from file").messageChain - RestUtils.toJsonError(None, message)(action, true) + RestUtils.response(restExtractor, "secrets", None)(res, req, "Error when trying to get all secrets") + } + } + + object GetSecret extends LiftApiModule { + val schema = API.GetSecret + val restExtractor = restExtractorService + + def process(version: ApiVersion, path: ApiPath, id: String, req: Req, params: DefaultParams, authzToken: AuthzToken): LiftResponse = { + implicit val prettify = params.prettify + implicit val action = schema.name + + val res = for { + secret <- secretService.getSecretById(id).notOptional(s"Could not find secret with `${id}` name").toBox + } yield { + JArray(List(Secret.serializeSecretInfo(secret))) } + + RestUtils.response(restExtractor, "secrets", None)(res, req, s"Error when trying to get secret `${id}` value") } } @@ -104,18 +117,12 @@ class SecretApi( val res = for { secret <- restExtractorService.extractSecret(req) - _ <- secretService.addSecret(secret).toBox + _ <- secretService.addSecret(secret, "Add a secret").toBox } yield { - Secret.serializeSecret(secret) + JArray(List(Secret.serializeSecretInfo(secret))) } - res match { - case Full(json) => - RestUtils.toJsonResponse(None, json) - case eb: EmptyBox => - val message = (eb ?~ s"Error when trying add a secret entry").messageChain - RestUtils.toJsonError(None, message)(action, true) - } + RestUtils.response(restExtractor, "secrets", None)(res, req, "Error when trying to add a secret") } } @@ -128,18 +135,16 @@ class SecretApi( implicit val action = schema.name val res = for { - _ <- secretService.deleteSecret(id).toBox + toDelete <- secretService.getSecretById(id).toBox + _ <- secretService.deleteSecret(id, "Delete a secret").toBox } yield { - id + toDelete match { + case Some(s) => JArray(List(Secret.serializeSecretInfo(s))) + case None => JArray(List(Secret.serializeSecretInfo(Secret(id, "", "")))) // don't know what to do here + } } - res match { - case Full(secretId) => - RestUtils.toJsonResponse(None, secretId) - case eb: EmptyBox => - val message = (eb ?~ s"Error when trying delete a secret entry").messageChain - RestUtils.toJsonError(None, message)(action, true) - } + RestUtils.response(restExtractor, "secrets", None)(res, req, "Error when trying to delete a secret") } } @@ -153,17 +158,12 @@ class SecretApi( val res = for { secret <- restExtractorService.extractSecret(req) - _ <- secretService.updateSecret(secret).toBox + _ <- secretService.updateSecret(secret, "Update a secret").toBox } yield { - Secret.serializeSecret(secret) - } - res match { - case Full(json) => - RestUtils.toJsonResponse(None, json) - case eb: EmptyBox => - val message = (eb ?~ s"Error when trying update a secret entry").messageChain - RestUtils.toJsonError(None, message)(action, true) + JArray(List(Secret.serializeSecretInfo(secret))) } + + RestUtils.response(restExtractor, "secrets", None)(res, req, s"Error when trying to update a secret") } } diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/web/services/EventLogDetailsGenerator.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/web/services/EventLogDetailsGenerator.scala index 8c13ec0e321..bd8d73b712a 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/web/services/EventLogDetailsGenerator.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/web/services/EventLogDetailsGenerator.scala @@ -827,15 +827,23 @@ class EventLogDetailsGenerator( case mod:ModifySecret => "*" #> { logDetailsService.getSecretModifyDetails(mod.details) match { case Full(modDiff) => + val hasChanged = { + if(modDiff.modValue) + Some(

The value has been changed

) + else + None + }

Secret overview:

  • Secret name: { modDiff.name }
  • +
  • Secret description: { modDiff.description }
{( "#name" #> modDiff.name & - "#value" #> mapSimpleDiff(modDiff.modValue) + "#value" #> hasChanged & + "#description" #> mapSimpleDiff(modDiff.modDescription) )(secretModDetailsXML) } { reasonHtml } @@ -1188,9 +1196,7 @@ class EventLogDetailsGenerator( private[this] def secretDetails(xml: NodeSeq, secret: Secret) = ( "#name" #> secret.name & - "#value" #> secret.value -// & -// "#description" #> globalParameter.description + "#description" #> secret.description )(xml) private[this] def apiAccountDetails(xml: NodeSeq, apiAccount: ApiAccount) = ( @@ -1328,7 +1334,7 @@ class EventLogDetailsGenerator(

Secret overview:

  • Name: 
  • -
  • Value: 
  • +
  • Description: 
@@ -1428,6 +1434,7 @@ class EventLogDetailsGenerator( {liModDetailsXML("name", "Name")} {liModDetailsXML("value", "Value")} + {liModDetailsXML("description", "Description")} diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/web/services/SecretService.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/web/services/SecretService.scala index b100ccca1e7..c743a113c02 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/web/services/SecretService.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/web/services/SecretService.scala @@ -38,12 +38,17 @@ package com.normation.rudder.web.services import better.files.File import com.normation.NamedZioLogger +import com.normation.cfclerk.services.GitRepositoryProvider import com.normation.errors.IOResult import com.normation.errors.Inconsistency import com.normation.eventlog.ModificationId +import com.normation.rudder.domain.eventlog.RudderEventActor import com.normation.rudder.domain.secrets._ import com.normation.rudder.repository.EventLogRepository +import com.normation.rudder.repository.GitModificationRepository import com.normation.rudder.web.services.CurrentUserService.actor +import com.normation.rudder.repository.xml._ +import com.normation.rudder.services.user.PersonIdentService import com.normation.utils.StringUuidGenerator import net.liftweb.json.JsonAST.JValue import net.liftweb.json.JsonDSL._ @@ -55,19 +60,28 @@ import zio.syntax._ import java.nio.charset.StandardCharsets trait SecretService { - def getSecrets: IOResult[List[Secret]] - def addSecret(s: Secret): IOResult[Unit] - def deleteSecret(secretId: String): IOResult[Unit] - def updateSecret(newSecret: Secret): IOResult[Unit] + def getAllSecret: IOResult[List[Secret]] + def getSecretById(secretId: String): IOResult[Option[Secret]] + def addSecret(s: Secret, reason: String): IOResult[Unit] + def deleteSecret(secretId: String, reason: String): IOResult[Unit] + def updateSecret(newSecret: Secret, reason: String): IOResult[Unit] } class FileSystemSecretRepository( - jsonDbPath : String - , actionLogger : EventLogRepository - , uuidGen : StringUuidGenerator -) extends SecretService { + jsonDbPath : String + , actionLogger : EventLogRepository + , uuidGen : StringUuidGenerator + , personIdentService : PersonIdentService + , override val gitRepo : GitRepositoryProvider + , override val gitRootDirectory : java.io.File + , override val xmlPrettyPrinter : RudderPrettyPrinter + , override val gitModificationRepository: GitModificationRepository + , override val encoding : String + , override val groupOwner : String +) extends SecretService with GitArchiverUtils { - private val secretsFile = File(jsonDbPath) + override val relativePath = "secrets" + private val secretsFile = File(s"/var/rudder/configuration-repository/${jsonDbPath}") val logger = NamedZioLogger(this.getClass.getName) private[this] def parseVersion1(json: JValue): IOResult[List[Secret]] = { @@ -90,6 +104,8 @@ class FileSystemSecretRepository( } def init(version: String): IOResult[Unit] = { + val modId = ModificationId(uuidGen.newUuid) + val json = s""" | { @@ -100,35 +116,43 @@ class FileSystemSecretRepository( | } | |""".stripMargin - for { - _ <- ZIO.when(secretsFile.notExists){ - IOResult.effect{ - val f = secretsFile.createFileIfNotExists(createParents = true) - f.write(json) - } - } - } yield () + + ZIO.when(secretsFile.notExists) { + IOResult.effect { + val f = secretsFile.createFileIfNotExists(createParents = true) + f.write(json) + for { + ident <- personIdentService.getPersonIdentOrDefault(RudderEventActor.name) + _ <- commitAddFile(modId, ident, secretsFile.canonicalPath, "Create secrets file") + } yield () + } + } } - override def getSecrets: IOResult[List[Secret]] = { + override def getAllSecret: IOResult[List[Secret]] = { for { s <- getSecretJsonContent } yield s } + override def getSecretById(id: String): IOResult[Option[Secret]] = { + for { + s <- getSecretJsonContent + } yield s.find(_.name == id) + } + private[this] def replaceInFile(formatVersion: String, secrets: List[Secret]): IOResult[Unit] = { IOResult.effect{ secretsFile.clear() val json = ( ("formatVersion" -> formatVersion) - ~ ("secrets" -> secrets.map(Secret.serializeSecret)) + ~ ("secrets" -> secrets.map(serializeSecret)) ) secretsFile.write(net.liftweb.json.prettyRender(json)) } } - override def addSecret(secToAdd: Secret): IOResult[Unit] = { - val reason = "Add a secret" + override def addSecret(secToAdd: Secret, reason: String): IOResult[Unit] = { val modId = ModificationId(uuidGen.newUuid) val formatVersion = "1.0" @@ -150,13 +174,15 @@ class FileSystemSecretRepository( _ <- actionLogger.saveAddSecret(modId, actor, secToAdd, Some(reason)).catchAll { e => logger.error(s"Error when trying to create event log `${modId.value}` for adding secret `${secToAdd.name}`, cause : ${e.fullMsg}") } + ident <- personIdentService.getPersonIdentOrDefault(RudderEventActor.name) + _ <- commitAddFile(modId, ident, secretsFile.canonicalPath, "Saving added Secret") + } yield () } } yield () } - override def deleteSecret(secretId: String): IOResult[Unit] = { - val reason = "Delete a secret" + override def deleteSecret(secretId: String, reason: String): IOResult[Unit] = { val modId = ModificationId(uuidGen.newUuid) val formatVersion = "1.0" for { @@ -171,15 +197,16 @@ class FileSystemSecretRepository( _ <- actionLogger.saveDeleteSecret(modId, actor, secToDel, Some(reason)).catchAll { e => logger.error(s"Error when trying to create event log `${modId.value}` for deleting secret `${secToDel.name}`, cause : ${e.fullMsg}") } + ident <- personIdentService.getPersonIdentOrDefault(RudderEventActor.name) + _ <- commitAddFile(modId, ident, secretsFile.canonicalPath, "Saving deleted Secret") } yield () case None => - logger.warn(s"Trying to delete secret ${secretId} but it doesn't exists") + logger.warn(s"Trying to delete secret ${secretId} but it doesn't exist") } } yield () } - override def updateSecret(newSecret: Secret): IOResult[Unit] = { - val reason = "Update a secret" + override def updateSecret(newSecret: Secret, reason: String): IOResult[Unit] = { val modId = ModificationId(uuidGen.newUuid) val formatVersion = "1.0" for { @@ -188,8 +215,8 @@ class FileSystemSecretRepository( oldSecret = secrets.find(_.name == newSecret.name) _ <- oldSecret match { case Some(oldSec) => - if(oldSec.value == newSecret.value) { - logger.warn(s"Trying to update secret `${oldSec.name}` with the same value") + if(oldSec.value == newSecret.value && oldSec.description == newSecret.description) { + UIO.unit } else { // Only one secret should be replaced here val newSecrets = secrets.map( s => if(s.name == newSecret.name) newSecret else s) @@ -198,11 +225,21 @@ class FileSystemSecretRepository( _ <- actionLogger.saveModifySecret(modId, actor, oldSec, newSecret, Some(reason)).catchAll { e => logger.error(s"Error when trying to update event log `${modId.value}` for updating secret `${oldSec.name}`, cause : ${e.fullMsg}") } + ident <- personIdentService.getPersonIdentOrDefault(RudderEventActor.name) + _ <- commitAddFile(modId, ident, secretsFile.canonicalPath, "Saving updated Secret") + } yield () } case None => - Inconsistency(s"Error when trying to update secret `${newSecret.name}`, this secret doesn't exists").fail + Inconsistency(s"Error when trying to update secret `${newSecret.name}`, this secret doesn't exist").fail } } yield () } + + private[this] def serializeSecret(secret : Secret): JValue = { + ( ("name" -> secret.name) + ~ ("description" -> secret.description) + ~ ("value" -> secret.value) + ) + } } diff --git a/webapp/sources/rudder/rudder-web/src/main/scala/bootstrap/liftweb/RudderConfig.scala b/webapp/sources/rudder/rudder-web/src/main/scala/bootstrap/liftweb/RudderConfig.scala index bacd1cab8a5..29e504ca4e3 100644 --- a/webapp/sources/rudder/rudder-web/src/main/scala/bootstrap/liftweb/RudderConfig.scala +++ b/webapp/sources/rudder/rudder-web/src/main/scala/bootstrap/liftweb/RudderConfig.scala @@ -841,9 +841,16 @@ object RudderConfig extends Loggable { val restCompletion = new RestCompletion(new RestCompletionService(roDirectiveRepository, roRuleRepository)) val secretVaultService = new FileSystemSecretRepository( - "/var/rudder/configuration-repository/secrets.json" + "secrets/secrets.json" , eventLogRepository , stringUuidGenerator + , personIdentService + , gitRepo + , new File(RUDDER_DIR_GITROOT) + , prettyPrinter + , gitModificationRepository + , RUDDER_CHARSET.name + , RUDDER_GROUP_OWNER_CONFIG_REPO ) val ruleApiService2 =