Skip to content

Commit 20e5aed

Browse files
committed
Merge pull request #144 from hindsightsoftware/default-appUser
Use normalizedName as the default appUser for Linux Packages
2 parents c038753 + 88bb292 commit 20e5aed

File tree

5 files changed

+47
-19
lines changed

5 files changed

+47
-19
lines changed

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,10 @@ For debian packaging there are a few things generated for you
7575
* A template folder `/var/log/<app-name>`
7676
* A symlink `/installdir/<app-name>/logs` to `/var/log/<app-name` (Installdir is by default `/usr/share`)
7777
* Default `serverLoading` is `Upstart` (you can choose SystemV with `com.typesafe.sbt.packager.archetypes.ServerLoader.SystemV` )
78-
* Default `daemonUser` is _root_
79-
* If you choose different permissions than the default ones for your packages, _add-user_ and _remove-user_ statements will be added to
80-
the `postrm` and `postinst` control files
78+
* Default `appUser` is the normalized name of the package
79+
* Default `daemonUser` is `appUser`
80+
* _add-user_ and _remove-user_ statements will be added to
81+
the `postrm` and `postinst` control files for `appUser`
8182

8283
### By-hand packaging ###
8384

src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala

+25-4
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ package debian
44

55
import Keys._
66
import sbt._
7-
import sbt.Keys.{ mappings, target, name, mainClass, normalizedName }
7+
import sbt.Keys.{ target, name, normalizedName, TaskStreams }
88
import linux.LinuxPackageMapping
9-
import linux.LinuxSymlink
109
import linux.LinuxFileMetaData
1110
import com.typesafe.sbt.packager.Hashing
1211
import com.typesafe.sbt.packager.linux.LinuxSymlink
1312
import com.typesafe.sbt.packager.archetypes.TemplateWriter
1413

1514
trait DebianPlugin extends Plugin with linux.LinuxPlugin {
1615
val Debian = config("debian") extend Linux
16+
val UserNamePattern = "^[a-z][-a-z0-9_]*$".r
1717

1818
import com.typesafe.sbt.packager.universal.Archives
1919
import DebianPlugin.Names
@@ -57,6 +57,15 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin {
5757
}
5858

5959

60+
private[this] def createFileIfRequired(script: File, perms: LinuxFileMetaData): File = {
61+
if (!script.exists()) {
62+
script.createNewFile()
63+
chmod(script, perms.permissions)
64+
}
65+
script
66+
}
67+
68+
6069
private[this] def scriptMapping(scriptName: String)(script: Option[File], controlDir: File): Seq[(File, String)] = {
6170
(script, controlDir) match {
6271
// check if user defined script exists
@@ -67,6 +76,15 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin {
6776
}
6877
}
6978

79+
private[this] def validateUserGroupNames(user: String, streams: TaskStreams) {
80+
if ((UserNamePattern findFirstIn user).isEmpty) {
81+
streams.log.warn("The user or group '" + user + "' may contain invalid characters for Debian based distributions")
82+
}
83+
if (user.length > 32) {
84+
streams.log.warn("The length of '" + user + "' must be not be greater than 32 characters for Debian based distributions.")
85+
}
86+
}
87+
7088

7189
def debianSettings: Seq[Setting[_]] = Seq(
7290
debianPriority := "optional",
@@ -172,8 +190,8 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin {
172190
} groupBy (_._1) foreach {
173191
case ((user, group), pathList) =>
174192
streams.log info ("Altering postrm/postinst files to add user " + user + " and group " + group)
175-
val postinst = t / Names.Debian / Names.Postinst
176-
val postrm = t / Names.Debian / Names.Postrm
193+
val postinst = createFileIfRequired(t / Names.Debian / Names.Postinst, LinuxFileMetaData())
194+
val postrm = createFileIfRequired(t / Names.Debian / Names.Postrm, LinuxFileMetaData())
177195

178196
val replacements = Seq("group" -> group, "user" -> user)
179197

@@ -185,6 +203,9 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin {
185203
prependAndFixPerms(postinst, chownAdd, LinuxFileMetaData())
186204
}
187205

206+
validateUserGroupNames(user, streams)
207+
validateUserGroupNames(group, streams)
208+
188209
val userGroupAdd = Seq(
189210
TemplateWriter.generateScript(DebianPlugin.postinstGroupaddTemplateSource, replacements),
190211
TemplateWriter.generateScript(DebianPlugin.postinstUseraddTemplateSource, replacements)

src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package linux
44

55
import Keys._
66
import sbt._
7+
import sbt.Keys.{ normalizedName }
78
import com.typesafe.sbt.packager.linux.LinuxPlugin.Users
89

910
/**
@@ -27,7 +28,7 @@ trait LinuxPlugin extends Plugin {
2728
},
2829
packageSummary in Linux <<= packageSummary,
2930
packageDescription in Linux <<= packageDescription,
30-
appUser := Users.Root, appGroup <<= appUser in Linux)
31+
appUser <<= normalizedName, appGroup <<= appUser in Linux)
3132

3233
/** DSL for packaging files into .deb */
3334
def packageMapping(files: (File, String)*) = LinuxPackageMapping(files)

src/sphinx/archetypes.rst

+5-2
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,18 @@ For Debian servers, you can select to either use SystemV or Upstart for your ser
108108
109109
serverLoading in Debian := ServerLoader.SystemV
110110
111-
By default, the native packager will install and run services using the ``root`` user and group. This is not a good default for services, which should not be exposed to root access. You can change the installation and usage user via the ``daemonUser`` key:
111+
By default, the native packager will install and run services using a user and group based on your package name. You can change the installation and usage user via the ``appUser`` and ``appGroup`` key:
112112

113113
.. code-block:: scala
114114
115-
daemonUser in Debian := "my_app_user"
115+
appUser in Linux := "my_app_user"
116+
117+
appGroup in Linux := "my_app_group"
116118
117119
The archetype will automatically append/prepend the creation/deletion of the user
118120
to your packaging for Debian. *Note:* All specified users are **deleted** on an ``apt-get purge <dpkg>``.
119121

122+
*Note:* It is not a good idea to use **root** as the ``appUser`` for services as it represents a security risk.
120123

121124

122125

src/sphinx/debian.rst

+11-9
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ can add ``preinst`` , ``postinst`` , ``prerm`` and/or ``postrm`` scripts. Just p
128128

129129
If you use the ``packageArchetype.java_server`` there are predefined ``postinst`` and
130130
``preinst`` files, which start/stop the application on install/remove calls. Existing
131-
maintainer scripts will be extended not overidden.
131+
maintainer scripts will be extended not overridden.
132132

133133
Your control scripts are in a different castle.. directory? No problem.
134134

@@ -149,12 +149,14 @@ The default configuration looks like this (that means you don't have to add anyt
149149
import com.typesafe.sbt.packager.archetypes.ServerLoader.{Upstart, SystemV}
150150
151151
serverLoading := Upstart
152-
153-
daemonUser := "root"
154-
155-
Change these values as you need. When you change the ``daemonUser`` make sure
156-
you alter the ``packageMappings`` correctly. All users you define in the
157-
``packageMappings`` will be generated within in the ``postinst`` script and
158-
removed with ``apt-get purge`` through the ``postrm`` script.
159152
160-
For more informations look at the :ref:`Archetypes` page.
153+
The default configuration will create a default system user and group for ownerships of the
154+
installed files. This user will also be used to execute the daemon service so it does
155+
not run as the **root** user.
156+
157+
This default can be overridden using the ``appUser`` and ``appGroup`` keys, change
158+
these values as you need. The user or group you define in the appropriate keys will be
159+
created within in the ``postinst`` script and removed with ``apt-get purge`` through the
160+
``postrm`` script.
161+
162+
For more information look at the :ref:`Archetypes` page.

0 commit comments

Comments
 (0)