diff --git a/openscap-policies/pom-template.xml b/openscap-policies/pom-template.xml new file mode 100644 index 000000000..b76c72dec --- /dev/null +++ b/openscap-policies/pom-template.xml @@ -0,0 +1,152 @@ + + 4.0.0 + com.normation.plugins + openscap-policies + jar + + ${plugin-version} + + + com.normation.plugins + plugins-parent + ${rudder-branch}-${parent-version} + + + + OpenSCAP audits managed by Rudder + + + + openscappolicies + + + + + + + org.codehaus.mojo + properties-maven-plugin + + + maven-resources-plugin + + + maven-shade-plugin + + + + + + + + org.owasp.antisamy + antisamy + 1.5.9 + + + + + + + + + internal-default + + + !limited + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.0.0 + + + add-source + generate-sources + + add-source + + + + ${basedir}/src/main/scala-templates/default + + + + + + + + + + internal-limited + + + limited + + + + org.codehaus.mojo + templating-maven-plugin + 1.0.0 + + + filter-src + + filter-sources + + + ${basedir}/src/main/scala-templates/limited + ${project.build.directory}/generated + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.0.0 + + + add-license-checker-source + generate-sources + + add-source + + + + ${project.build.directory}/generated + + + + + + + + + com.normation.plugins + plugins-common-private + + + + + rudder-release-private + http://nexus.normation.com/nexus/content/repositories/private-releases/ + default + false + + + rudder-snapshot-private + http://nexus.normation.com/nexus/content/repositories/private-snapshots/ + default + true + + + + + + diff --git a/openscap-policies/src/main/resources/antisamy-slashdot.xml b/openscap-policies/src/main/resources/antisamy-slashdot.xml new file mode 100644 index 000000000..4e32d0286 --- /dev/null +++ b/openscap-policies/src/main/resources/antisamy-slashdot.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + grin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openscap-policies/src/main/resources/antisamy.xml b/openscap-policies/src/main/resources/antisamy.xml new file mode 100644 index 000000000..762813f65 --- /dev/null +++ b/openscap-policies/src/main/resources/antisamy.xml @@ -0,0 +1,2789 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + grin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openscap-policies/src/main/scala-templates/default/com/normation/plugins/openscappolicies/EnablePluginImpl.scala b/openscap-policies/src/main/scala-templates/default/com/normation/plugins/openscappolicies/EnablePluginImpl.scala new file mode 100644 index 000000000..ab6f05131 --- /dev/null +++ b/openscap-policies/src/main/scala-templates/default/com/normation/plugins/openscappolicies/EnablePluginImpl.scala @@ -0,0 +1,48 @@ +/* +************************************************************************************* +* Copyright 2020 Normation SAS +************************************************************************************* +* +* This file is part of Rudder. +* +* Rudder is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* In accordance with the terms of section 7 (7. Additional Terms.) of +* the GNU General Public License version 3, the copyright holders add +* the following Additional permissions: +* Notwithstanding to the terms of section 5 (5. Conveying Modified Source +* Versions) and 6 (6. Conveying Non-Source Forms.) of the GNU General +* Public License version 3, when you create a Related Module, this +* Related Module is not considered as a part of the work and may be +* distributed under the license agreement of your choice. +* A "Related Module" means a set of sources files including their +* documentation that, without modification of the Source Code, enables +* supplementary functions or services in addition to those offered by +* the Software. +* +* Rudder is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Rudder. If not, see . + +* +************************************************************************************* +*/ + +package com.normation.plugins.openscappolicies + +import com.normation.plugins.PluginEnableImpl +import com.normation.rudder.services.nodes.NodeInfoService + +/* + * The class will be loaded by ServiceLoader, it needs an empty constructor. + */ + +final class CheckRudderPluginEnableImpl(nodeInfoService: NodeInfoService) extends PluginEnableImpl + diff --git a/openscap-policies/src/main/scala-templates/limited/com/normation/plugins/openscappolicies/EnablePluginImpl.scala b/openscap-policies/src/main/scala-templates/limited/com/normation/plugins/openscappolicies/EnablePluginImpl.scala new file mode 100644 index 000000000..1123bc42f --- /dev/null +++ b/openscap-policies/src/main/scala-templates/limited/com/normation/plugins/openscappolicies/EnablePluginImpl.scala @@ -0,0 +1,59 @@ +/* +************************************************************************************* +* Copyright 2020 Normation SAS +************************************************************************************* +* +* This file is part of Rudder. +* +* Rudder is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* In accordance with the terms of section 7 (7. Additional Terms.) of +* the GNU General Public License version 3, the copyright holders add +* the following Additional permissions: +* Notwithstanding to the terms of section 5 (5. Conveying Modified Source +* Versions) and 6 (6. Conveying Non-Source Forms.) of the GNU General +* Public License version 3, when you create a Related Module, this +* Related Module is not considered as a part of the work and may be +* distributed under the license agreement of your choice. +* A "Related Module" means a set of sources files including their +* documentation that, without modification of the Source Code, enables +* supplementary functions or services in addition to those offered by +* the Software. +* +* Rudder is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Rudder. If not, see . + +* +************************************************************************************* +*/ + +package com.normation.plugins.openscappolicies + +import com.normation.plugins.LicensedPluginCheck +import com.normation.rudder.services.nodes.NodeInfoService + +/* + * This template file will processed at build time to choose + * the correct immplementation to use for the interface. + * The default implementation is to always enable status. + * + * The class will be loaded by ServiceLoader, it needs an empty constructor. + */ +final class CheckRudderPluginEnableImpl(nodeInfoService: NodeInfoService) extends LicensedPluginCheck { + // here are processed variables + def pluginResourcePublickey = "${plugin-resource-publickey}" + def pluginResourceLicense = "${plugin-resource-license}" + def pluginDeclaredVersion = "${plugin-declared-version}" + def pluginId = "${plugin-fullname}" + + override def getNumberOfNodes: Int = nodeInfoService.getNumberOfManagedNodes +} + diff --git a/openscap-policies/src/main/scala/bootstrap/rudder/plugin/OpenscapPoliciesConf.scala b/openscap-policies/src/main/scala/bootstrap/rudder/plugin/OpenscapPoliciesConf.scala new file mode 100644 index 000000000..ed8e783d4 --- /dev/null +++ b/openscap-policies/src/main/scala/bootstrap/rudder/plugin/OpenscapPoliciesConf.scala @@ -0,0 +1,68 @@ +/* +************************************************************************************* +* Copyright 2020 Normation SAS +************************************************************************************* +* +* This file is part of Rudder. +* +* Rudder is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* In accordance with the terms of section 7 (7. Additional Terms.) of +* the GNU General Public License version 3, the copyright holders add +* the following Additional permissions: +* Notwithstanding to the terms of section 5 (5. Conveying Modified Source +* Versions) and 6 (6. Conveying Non-Source Forms.) of the GNU General +* Public License version 3, when you create a Related Module, this +* Related Module is not considered as a part of the work and may be +* distributed under the license agreement of your choice. +* A "Related Module" means a set of sources files including their +* documentation that, without modification of the Source Code, enables +* supplementary functions or services in addition to those offered by +* the Software. +* +* Rudder is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Rudder. If not, see . + +* +************************************************************************************* +*/ + +package bootstrap.rudder.plugin + +import bootstrap.liftweb.RudderConfig +import com.normation.plugins.openscappolicies.OpenscapPoliciesPluginDef +import com.normation.plugins.openscappolicies.CheckRudderPluginEnableImpl +import net.liftweb.common.Loggable +import com.normation.plugins.RudderPluginModule +import com.normation.plugins.openscappolicies.api.OpenScapApiImpl +import com.normation.plugins.openscappolicies.extension.OpenScapNodeDetailsExtension +import com.normation.plugins.openscappolicies.services.{OpenScapReportReader, ReportSanitizer} + +/* + * Actual configuration of the plugin logic + */ +object OpenscapPoliciesConf extends RudderPluginModule { + + val POLICY_SANITIZATION_FILE = "/home/nicolas/dev/rudder-plugins/openscap-policies/src/main/resources/antisamy.xml" + // by build convention, we have only one of that on the classpath + lazy val pluginStatusService = new CheckRudderPluginEnableImpl(RudderConfig.nodeInfoService) + + lazy val pluginDef = new OpenscapPoliciesPluginDef(OpenscapPoliciesConf.pluginStatusService) + + lazy val reportSanitizer = new ReportSanitizer(POLICY_SANITIZATION_FILE) + lazy val openScapReportReader = new OpenScapReportReader(RudderConfig.nodeInfoService) + + lazy val openScapApiImpl = new OpenScapApiImpl(RudderConfig.restExtractorService, openScapReportReader, reportSanitizer) + // other service instanciation / initialization + RudderConfig.snippetExtensionRegister.register(new OpenScapNodeDetailsExtension(pluginStatusService, openScapReportReader, reportSanitizer)) + + +} diff --git a/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/DataTypes.scala b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/DataTypes.scala new file mode 100644 index 000000000..42a2790ee --- /dev/null +++ b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/DataTypes.scala @@ -0,0 +1,57 @@ +/* +************************************************************************************* +* Copyright 2020 Normation SAS +************************************************************************************* +* +* This file is part of Rudder. +* +* Rudder is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* In accordance with the terms of section 7 (7. Additional Terms.) of +* the GNU General Public License version 3, the copyright holders add +* the following Additional permissions: +* Notwithstanding to the terms of section 5 (5. Conveying Modified Source +* Versions) and 6 (6. Conveying Non-Source Forms.) of the GNU General +* Public License version 3, when you create a Related Module, this +* Related Module is not considered as a part of the work and may be +* distributed under the license agreement of your choice. +* A "Related Module" means a set of sources files including their +* documentation that, without modification of the Source Code, enables +* supplementary functions or services in addition to those offered by +* the Software. +* +* Rudder is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Rudder. If not, see . + +* +************************************************************************************* +*/ + +package com.normation.plugins.openscappolicies + +import java.io.FileNotFoundException + +import com.normation.inventory.domain.NodeId +import net.liftweb.common._ +import org.slf4j.LoggerFactory +import org.xml.sax.SAXParseException + +import scala.xml._ + +/** + * Applicative log of interest for Rudder ops. + */ +object OpenscapPoliciesLogger extends Logger { + override protected def _logger = LoggerFactory.getLogger("openscap-policies") +} + +// other data types for you plugin +case class OpenScapReport(nodeId: NodeId, content: String) \ No newline at end of file diff --git a/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/OpenscapPoliciesPluginDef.scala b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/OpenscapPoliciesPluginDef.scala new file mode 100644 index 000000000..99cb939ea --- /dev/null +++ b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/OpenscapPoliciesPluginDef.scala @@ -0,0 +1,83 @@ +/* +************************************************************************************* +* Copyright 2020 Normation SAS +************************************************************************************* +* +* This file is part of Rudder. +* +* Rudder is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* In accordance with the terms of section 7 (7. Additional Terms.) of +* the GNU General Public License version 3, the copyright holders add +* the following Additional permissions: +* Notwithstanding to the terms of section 5 (5. Conveying Modified Source +* Versions) and 6 (6. Conveying Non-Source Forms.) of the GNU General +* Public License version 3, when you create a Related Module, this +* Related Module is not considered as a part of the work and may be +* distributed under the license agreement of your choice. +* A "Related Module" means a set of sources files including their +* documentation that, without modification of the Source Code, enables +* supplementary functions or services in addition to those offered by +* the Software. +* +* Rudder is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Rudder. If not, see . + +* +************************************************************************************* +*/ + +package com.normation.plugins.openscappolicies + +import bootstrap.liftweb.Boot +import bootstrap.rudder.plugin.OpenscapPoliciesConf +import com.normation.plugins._ +import com.normation.rudder.AuthorizationType.Administration +import com.normation.rudder.rest.EndpointSchema +import com.normation.rudder.rest.lift.LiftApiModuleProvider +import net.liftweb.http.ClasspathTemplates +import net.liftweb.sitemap.Loc.LocGroup +import net.liftweb.sitemap.Loc.Template +import net.liftweb.sitemap.Loc.TestAccess +import net.liftweb.sitemap.LocPath.stringToLocPath +import net.liftweb.sitemap.Menu + +class OpenscapPoliciesPluginDef(override val status: PluginStatus) extends DefaultPluginDef { + + override val basePackage = "com.normation.plugins.openscappolicies" + + def init = {} + + def oneTimeInit : Unit = {} + + override def apis: Option[LiftApiModuleProvider[_ <: EndpointSchema]] = { + Some(OpenscapPoliciesConf.openScapApiImpl) + } + + val configFiles = Seq() + + override def updateSiteMap(menus:List[Menu]) : List[Menu] = { + val OpenscapPoliciesMenu = ( + Menu("OpenscapPolicies", OpenSCAP Policies) / + "secure" / "administration" / "OpenscapPoliciesManagement" + >> LocGroup("administrationGroup") + >> TestAccess ( () => Boot.userIsAllowed("/secure/administration/policyServerManagement", Administration.Read)) + >> Template(() => ClasspathTemplates("template" :: "OpenscapPoliciesManagement" :: Nil ) openOr
Template not found
) + ) + + menus.map { + case m@Menu(l, _* ) if(l.name == "AdministrationHome") => + Menu(l , m.kids.toSeq :+ OpenscapPoliciesMenu:_* ) + case m => m + } + } + +} diff --git a/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/api/OpenScapApi.scala b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/api/OpenScapApi.scala new file mode 100644 index 000000000..ddb8486a8 --- /dev/null +++ b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/api/OpenScapApi.scala @@ -0,0 +1,130 @@ +package com.normation.plugins.openscappolicies.api + +import java.io.InputStream + +import com.normation.inventory.domain.NodeId +import com.normation.plugins.openscappolicies.OpenscapPoliciesLogger +import com.normation.plugins.openscappolicies.services.{OpenScapReportReader, ReportSanitizer} +import com.normation.rudder.api.HttpAction.{GET, PUT} +import com.normation.rudder.rest.EndpointSchema.syntax._ +import com.normation.rudder.rest.{ApiModuleProvider, EndpointSchema, GeneralApi, SortIndex, StartsAtVersion10, ZeroParam} +import com.normation.rudder.rest.EndpointSchema.syntax._ +import com.normation.rudder.rest._ +import com.normation.rudder.rest.lift.{DefaultParams, LiftApiModule, LiftApiModule0, LiftApiModuleProvider} +import net.liftweb.http.{InMemoryResponse, LiftResponse, OutputStreamResponse, Req} +import net.liftweb.json.JsonAST.JNothing +import net.liftweb.json.{JValue, NoTypeHints} +import net.liftweb.common.{Box, EmptyBox, Failure, Full} +import sourcecode.Line +import com.normation.box._ + +sealed trait OpenScapApi extends EndpointSchema with GeneralApi with SortIndex +object OpenScapApi extends ApiModuleProvider[OpenScapApi] { + + final case object GetOpenScapReport extends OpenScapApi with OneParam with StartsAtVersion10 { + val z = implicitly[Line].value + val description = "Get OpenScap report for a node" + val (action, path) = GET / "openscap" / "report" / "{id}" + } + + final case object GetSanitizedOpenScapReport extends OpenScapApi with OneParam with StartsAtVersion15 { + val z = implicitly[Line].value + val description = "Get sanitized OpenScap report for a node" + val (action, path) = GET / "openscap" / "sanitized" / "{id}" + } + + def endpoints = ca.mrvisser.sealerate.values[OpenScapApi].toList.sortBy( _.z ) +} + + +class OpenScapApiImpl( + restExtractorService: RestExtractorService + , openScapReportReader: OpenScapReportReader + , reportSanitizer : ReportSanitizer +) extends LiftApiModuleProvider[OpenScapApi] { + api => + + val logger = OpenscapPoliciesLogger + + implicit val formats = net.liftweb.json.Serialization.formats(NoTypeHints) + + def schemas = OpenScapApi + + def getLiftEndpoints(): List[LiftApiModule] = { + OpenScapApi.endpoints.map { case e => println(e); e match { + case OpenScapApi.GetOpenScapReport => GetOpenScapReport + case OpenScapApi.GetSanitizedOpenScapReport => GetSanitizedOpenScapReport + }}.toList + } + + def response(function: Box[JValue], req: Req, errorMessage: String, id: Option[String], dataName : String)(implicit action: String): LiftResponse = { + RestUtils.response(restExtractorService, dataName, id)(function, req, errorMessage) + } + + object GetOpenScapReport extends LiftApiModule { + val schema = OpenScapApi.GetOpenScapReport + val restExtractor = api.restExtractorService + + def process(version: ApiVersion, path: ApiPath, nodeId: String, req: Req, params: DefaultParams, authzToken: AuthzToken): LiftResponse = { + implicit val action = "getOpenScapReport" +println("process") + (for { + report <- openScapReportReader.getOpenScapReport(NodeId(nodeId)) + + } yield { + logger.info("found report for the API") + report + // OutputStreamResponse(InputStream(report.content)) + }) match { + case Full(report) => + logger.info("doing in memory response") + InMemoryResponse( + report.content.getBytes() + , ("Content-Type" -> "text/html") :: + ("Content-Disposition","""attachment;filename="rudder-openscap-%s.html"""".format(nodeId)) :: + Nil + , Nil + , 200) + case _ => + RestUtils.toJsonError(None, JNothing)(schema.name, params.prettify) + } + + } + } + + object GetSanitizedOpenScapReport extends LiftApiModule { + val schema = OpenScapApi.GetSanitizedOpenScapReport + val restExtractor = api.restExtractorService + + def process(version: ApiVersion, path: ApiPath, nodeId: String, req: Req, params: DefaultParams, authzToken: AuthzToken): LiftResponse = { + implicit val action = "getSanitizedOpenScapReport" + (for { + report <- openScapReportReader.getOpenScapReport(NodeId(nodeId)) ?~! s"Cannot get OpenScap Report for node ${nodeId}" + sanitizedXml <- reportSanitizer.sanitizeReport(report).toBox ?~! "Error while sanitizing report" + } yield { + logger.trace(s"Report for node ${nodeId} has been found and sanitized") + sanitizedXml + }) match { + case Full(sanitizedReport) => + logger.info("doing in memory response") + InMemoryResponse( + sanitizedReport.toString().getBytes() + // somehow, the X-FRAME-OPTIONS get rewrote to DENY here + , ("Content-Type", "text/html") :: ("Content-Disposition", "inline") :: Nil + , Nil + , 200) + case eb: EmptyBox => + val errorMessage = eb ?~! "Could not get the OpenScap report for node ${nodeId}" + logger.error(errorMessage.messageChain) + val html =
{errorMessage}
+ InMemoryResponse( + html.toString().getBytes() + , ("Content-Type", "text/html") :: ("Content-Disposition", "inline") :: Nil + , Nil + , 403) + } + + } + } + +} \ No newline at end of file diff --git a/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/extension/OpenScapNodeDetailsExtension.scala b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/extension/OpenScapNodeDetailsExtension.scala new file mode 100644 index 000000000..55d896e87 --- /dev/null +++ b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/extension/OpenScapNodeDetailsExtension.scala @@ -0,0 +1,88 @@ +package com.normation.plugins.openscappolicies.extension + +import com.normation.plugins.openscappolicies.OpenScapReport +import com.normation.plugins.openscappolicies.services.{OpenScapReportReader, ReportSanitizer} +import com.normation.plugins.{PluginExtensionPoint, PluginStatus} +import com.normation.rudder.web.components.ShowNodeDetailsFromNode +import net.liftweb.common.{EmptyBox, Full, Loggable} + +import scala.reflect.ClassTag +import scala.xml.NodeSeq +import net.liftweb.util.CssSel +import net.liftweb.util.Helpers._ +import com.normation.box._ +import com.normation.inventory.domain.NodeId + +class OpenScapNodeDetailsExtension( + val status: PluginStatus + , openScapReader: OpenScapReportReader + , reportSanitizer: ReportSanitizer)(implicit val ttag: ClassTag[ShowNodeDetailsFromNode]) extends PluginExtensionPoint[ShowNodeDetailsFromNode] with Loggable { + + def pluginCompose(snippet: ShowNodeDetailsFromNode) : Map[String, NodeSeq => NodeSeq] = Map( + "popupDetails" -> addExternalReportTab(snippet) _ + , "mainDetails" -> addExternalReportTab(snippet) _ + ) + + /** + * Add a tab: + * - add an li in ul with id=openScapExtensionTab + */ + def addExternalReportTab(snippet: ShowNodeDetailsFromNode)(xml: NodeSeq) = { + + val content = openScapReader.getOpenScapReport(snippet.nodeId) match { + case eb: EmptyBox => + val e = eb ?~! "Can not display OpenScap report for that node" + (
{e.messageChain}
) + case Full(report) => + reportSanitizer.sanitizeReport(report).toBox match { + case eb: EmptyBox => val e = eb ?~! "Cannot parse OpenScap report" + (
{e.messageChain}
) + case Full(x) => + frameContent(snippet.nodeId)(openScapExtensionXml) + } + + + } + + + //tabContent(Map("key" ->"value"))(openScapExtensionXml) + val tabTitle = "OpenScap" + + status.isEnabled() match { + case false => +
Plugin is disabled
+ case true => + ( + "#NodeDetailsTabMenu *" #> { (x: NodeSeq) => + x ++ ( +
  • + + {tabTitle} + +
  • + ) + } & + "#node_logs" #> { (x: NodeSeq) => + x ++ + content + } + ) (xml) + } + } + + def frameContent(nodeId : NodeId): CssSel = { + "iframe [src]" #> s"http://localhost:8080/rudder-parent/secure/api/openscap/sanitized/${nodeId.value}" + + } + + private def openScapExtensionXml = +
    +

    That tab gives access to OpenScap reports configured for that node

    + +
    +
    +

    [title]

    + +
    +
    +} diff --git a/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/services/OpenScapReportReader.scala b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/services/OpenScapReportReader.scala new file mode 100644 index 000000000..de1dab64d --- /dev/null +++ b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/services/OpenScapReportReader.scala @@ -0,0 +1,54 @@ +package com.normation.plugins.openscappolicies.services + +import com.normation.inventory.domain.NodeId +import com.normation.plugins.openscappolicies.{OpenScapReport, OpenscapPoliciesLogger} +import com.normation.rudder.services.nodes.NodeInfoService +import net.liftweb.common._ +import net.liftweb.util.Helpers.tryo +import better.files._ + + +/** + * Read the openscap report + * It is n /var/rudder/shared-files/root/NodeId/openscap.html + */ +class OpenScapReportReader(nodeInfoService: NodeInfoService) { + + val OPENSCAP_REPORT_FILENAME = "openscap.html" + val OPENSCAP_REPORT_PATH = "/var/rudder/shared-files/root/" + + val logger = OpenscapPoliciesLogger + /** + * For a given node, return the structure + * with the openscap report. + * If the file is not there, fails + */ + def getOpenScapReport(nodeId: NodeId): Box[OpenScapReport] = { + nodeInfoService.getNodeInfo(nodeId) match { + case t:EmptyBox => + val errMessage = s"Node with id ${nodeId} does not exists" + logger.error(errMessage) + Failure(errMessage) + case Full(id) => + id match { + case None => + val errMessage = s"Node with id ${nodeId} not found" + logger.error(errMessage) + Failure(errMessage) + case Some(nodeInfo) => + val path = OPENSCAP_REPORT_PATH + nodeInfo.id.value + "/" + OPENSCAP_REPORT_FILENAME + val reportFile = File(path) + if (!reportFile.exists()) { + val errMessage = s"OpenSCAP reports missing at location $path - can't show anything" + logger.error(errMessage) + Failure(errMessage) + } else { + // file exist, reading it + logger.debug(s"Loading report file at ${path}") + tryo(OpenScapReport(nodeId, reportFile.contentAsString)) + } + } + + } + } +} diff --git a/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/services/ReportSanitizer.scala b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/services/ReportSanitizer.scala new file mode 100644 index 000000000..815d301d7 --- /dev/null +++ b/openscap-policies/src/main/scala/com/normation/plugins/openscappolicies/services/ReportSanitizer.scala @@ -0,0 +1,25 @@ +package com.normation.plugins.openscappolicies.services + +import com.normation.errors.IOResult +import com.normation.plugins.openscappolicies.OpenScapReport +import org.owasp.validator.html._ + +import scala.xml.NodeSeq + +class ReportSanitizer(policyFile: String) { + + + val policy = Policy.getInstance(policyFile) + val as = new AntiSamy + + def sanitizeReport(input: OpenScapReport): IOResult[NodeSeq] = { + val cr = as.scan(input.content, policy) + + for { + report <- IOResult.effect (xml.XML.loadString(cr.getCleanHTML)) + //nonHeadedReport = report.filterNot(_.label == "head" ) + } yield { + report + } + } +} diff --git a/openscap-policies/src/test/resources/logback-test.xml b/openscap-policies/src/test/resources/logback-test.xml new file mode 100644 index 000000000..bc342ae4d --- /dev/null +++ b/openscap-policies/src/test/resources/logback-test.xml @@ -0,0 +1,45 @@ + + + + + + %d{[yyyy-MM-dd HH:mm:ss]} %-5level %logger - %msg%n%xEx{0} + + + + + + + +