]> source.dussan.org Git - gitblit.git/commitdiff
Moved distribution files. Revised build script. Security revisions.
authorJames Moger <james.moger@gitblit.com>
Thu, 12 May 2011 21:33:31 +0000 (17:33 -0400)
committerJames Moger <james.moger@gitblit.com>
Thu, 12 May 2011 21:33:31 +0000 (17:33 -0400)
36 files changed:
.gitignore
build.xml
distrib/JavaService.exe [new file with mode: 0644]
distrib/JavaService64.exe [new file with mode: 0644]
distrib/UninstallService.bat [new file with mode: 0644]
distrib/UninstallService64.bat [new file with mode: 0644]
distrib/gitblit-stop.cmd [new file with mode: 0644]
distrib/gitblit.cmd [new file with mode: 0644]
distrib/gitblit.properties [new file with mode: 0644]
distrib/installService.bat [new file with mode: 0644]
distrib/installService64.bat [new file with mode: 0644]
distrib/makekeystore_jdk.cmd [new file with mode: 0644]
distrib/users.properties [new file with mode: 0644]
gitblit.properties
service/JavaService.exe [deleted file]
service/JavaService64.exe [deleted file]
service/UninstallService.bat [deleted file]
service/UninstallService64.bat [deleted file]
service/installService.bat [deleted file]
service/installService64.bat [deleted file]
src/com/gitblit/Constants.java
src/com/gitblit/GitBlit.java
src/com/gitblit/GitBlitServer.java
src/com/gitblit/ILoginService.java
src/com/gitblit/JettyLoginService.java
src/com/gitblit/wicket/BasePage.java
src/com/gitblit/wicket/GitBlitWebApp.properties
src/com/gitblit/wicket/pages/EditRepositoryPage.html
src/com/gitblit/wicket/pages/EditRepositoryPage.java
src/com/gitblit/wicket/pages/EditUserPage.html
src/com/gitblit/wicket/pages/EditUserPage.java
src/com/gitblit/wicket/pages/RepositoriesPage.html
src/com/gitblit/wicket/pages/RepositoriesPage.java
src/com/gitblit/wicket/pages/SummaryPage.html
src/com/gitblit/wicket/pages/SummaryPage.java
users.properties

index 10d4ae886474276d5b09ab27230b0f8e2e0fc9c6..3ad2f7e8256bdbe878e513b0139963a3cf210095 100644 (file)
@@ -4,3 +4,4 @@
 /build
 /keystore
 /gitblit.zip
+/gitblit-0.1.0-SNAPSHOT.zip
index caaf34375f455e0bcdd9343659cf256d513d2659..22f233602c5e5127d692a324a2db94d5896c5b19 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -3,12 +3,35 @@
 \r
        <!-- Project Properties -->\r
        <property name="project.jar" value="gitblit.jar" />\r
-       <property name="project.mainclass" value="com.gitblit.Launcher" />\r
-       <property name="distribution.zipfile" value="gitblit.zip" />\r
+       <property name="project.mainclass" value="com.gitblit.Launcher" />      \r
        <property name="project.build.dir" value="${basedir}/build" />\r
 \r
        <target name="main">\r
-\r
+                       \r
+               <!-- extract version number from source code -->\r
+               <loadfile property="gb.version" srcfile="${basedir}/src/com/gitblit/Constants.java">\r
+                       <filterchain>\r
+                               <linecontains>\r
+                               <contains value="public final static String VERSION = "/>\r
+                       </linecontains>\r
+                               <striplinebreaks/>\r
+                               <tokenfilter>                               \r
+                                       <replacestring from="public final static String VERSION = &quot;" to=""/>\r
+                                       <replacestring from="&quot;;" to=""/>\r
+                                       <trim />\r
+                               </tokenfilter>\r
+                       </filterchain>\r
+               </loadfile>\r
+               <echo>Building Git:Blit ${gb.version}</echo>\r
+               \r
+               <!-- copy required distribution files to project folder -->\r
+               <copy todir="${basedir}" overwrite="false">\r
+                       <fileset dir="${basedir}/distrib">\r
+                               <include name="gitblit.properties" />\r
+                               <include name="users.properties" />\r
+                       </fileset>\r
+               </copy>\r
+               \r
                <!-- Compile the build tool and execute it.\r
                         This downloads missing compile-time dependencies from Maven. -->\r
 \r
                <mkdir dir="${basedir}/deploy" />\r
                <copy todir="${basedir}/deploy" file="${project.jar}" />\r
                <copy todir="${basedir}/deploy">\r
-                       <fileset dir="${basedir}/service">\r
+                       <fileset dir="${basedir}/distrib">\r
                                <include name="**/*" />\r
                        </fileset>\r
-                       <fileset dir="${basedir}">\r
-                               <include name="*.cmd" />\r
-                               <include name="*.properties" />\r
-                       </fileset>\r
                </copy>\r
 \r
                <!-- Create Zip deployment -->\r
+               <property name="distribution.zipfile" value="gitblit-${gb.version}.zip" />\r
                <zip destfile="${distribution.zipfile}">\r
                        <fileset dir="${basedir}/deploy">\r
                                <include name="**/*" />\r
diff --git a/distrib/JavaService.exe b/distrib/JavaService.exe
new file mode 100644 (file)
index 0000000..8755955
Binary files /dev/null and b/distrib/JavaService.exe differ
diff --git a/distrib/JavaService64.exe b/distrib/JavaService64.exe
new file mode 100644 (file)
index 0000000..fb32708
Binary files /dev/null and b/distrib/JavaService64.exe differ
diff --git a/distrib/UninstallService.bat b/distrib/UninstallService.bat
new file mode 100644 (file)
index 0000000..a483c55
--- /dev/null
@@ -0,0 +1 @@
+javaservice -uninstall gitblit
\ No newline at end of file
diff --git a/distrib/UninstallService64.bat b/distrib/UninstallService64.bat
new file mode 100644 (file)
index 0000000..91f0c84
--- /dev/null
@@ -0,0 +1 @@
+javaservice64 -uninstall gitblit
\ No newline at end of file
diff --git a/distrib/gitblit-stop.cmd b/distrib/gitblit-stop.cmd
new file mode 100644 (file)
index 0000000..c139d57
--- /dev/null
@@ -0,0 +1 @@
+@java -jar gitblit.jar --stop\r
diff --git a/distrib/gitblit.cmd b/distrib/gitblit.cmd
new file mode 100644 (file)
index 0000000..ce96a79
--- /dev/null
@@ -0,0 +1 @@
+@java -jar gitblit.jar\r
diff --git a/distrib/gitblit.properties b/distrib/gitblit.properties
new file mode 100644 (file)
index 0000000..6bf33f1
--- /dev/null
@@ -0,0 +1,159 @@
+#\r
+# Git Servlet Settings\r
+#\r
+\r
+# Allow push/pull over http/https with JGit servlet\r
+git.enableGitServlet = true\r
+\r
+# Base folder for repositories\r
+# Use forward slashes even on Windows!!\r
+git.repositoriesFolder = c:/git\r
+\r
+# Export all repositories\r
+# if false, each exported repository must have a .git/git-daemon-export-ok file\r
+git.exportAll = true\r
+\r
+# Search repositories folder for nested repositories\r
+# e.g. /libraries/mylibrary.git\r
+git.nestedRepositories = true\r
+\r
+# The root clone url\r
+git.cloneUrl = https://localhost/git/\r
+\r
+#\r
+# Authentication Settings\r
+#\r
+\r
+# Require authentication to see everything but the admin pages\r
+web.authenticateViewPages = false\r
+\r
+# Require admin authentication for the admin functions and pages\r
+web.authenticateAdminPages = true\r
+\r
+# Simple user realm file to authenticate users\r
+realm.realmFile = users.properties\r
+\r
+# How to store passwords.\r
+# Valid values are plain, md5 or crypt (unix style).  Default is md5. \r
+realm.passwordStorage = md5\r
+\r
+#\r
+# Git:Blit Web Settings\r
+#\r
+# If blank Git:Blit is displayed.\r
+web.siteName =\r
+\r
+# If web.authenticate=true, users with "admin" role can create repositories,\r
+# create users, and edit repository metadata (owner, description, etc)\r
+#\r
+# If web.authenticate=false, any user can execute the aforementioned functions.  \r
+web.allowAdministration = true\r
+\r
+# This is the message display above the repositories table.\r
+# This can point to a file with Markdown content.\r
+# Specifying "gitblit" uses the internal welcome message.\r
+web.repositoriesMessage = gitblit\r
+\r
+# Use the client timezone when formatting dates.\r
+# This uses AJAX to determine the browser's timezone.\r
+web.useClientTimezone = false\r
+\r
+# Date and Time formats\r
+web.datestampShortFormat = yyyy-MM-dd\r
+web.datetimestampLongFormat = EEEE, MMMM d, yyyy h:mm a z\r
+\r
+# Choose the diff presentation style: gitblt, gitweb, or plain\r
+web.diffStyle = gitblit\r
+\r
+# Control if email addresses are shown in web ui\r
+web.showEmailAddresses = true\r
+\r
+# Shows a combobox in the page links header with commit, committer, and author\r
+# search selection.  Default search is commit.\r
+web.showSearchTypeSelection = false\r
+\r
+# Generates a line graph of repository activity over time on the Summary page.\r
+# This is a real-time graph so generation may be expensive. \r
+web.generateActivityGraph = true\r
+\r
+# The number of commits to display on the summary page\r
+# Value must exceed 0 else default of 20 is used\r
+web.summaryCommitCount = 16\r
+\r
+# The number of tags/heads to display on the summary page\r
+# Value must exceed 0 else default of 5 is used\r
+web.summaryRefsCount = 5\r
+\r
+# The number of items to show on a page before showing the first, prev, next\r
+# pagination links.  A default if 50 is used for any invalid value.\r
+web.itemsPerPage = 50\r
+\r
+# Registered extensions for google-code-prettify\r
+web.prettyPrintExtensions = c cpp cs css htm html java js php pl prefs properties py rb sh sql xml vb\r
+\r
+# Registered extensions for markdown transformation\r
+web.markdownExtensions = md mkd markdown\r
+\r
+# Image extensions\r
+web.imageExtensions = bmp jpg gif png \r
+\r
+# Registered extensions for binary blobs\r
+web.binaryExtensions = jar pdf tar.gz zip\r
+\r
+# Aggressive heap management will run the garbage collector on every generated\r
+# page.  This slows down page generation but improves heap consumption. \r
+web.aggressiveHeapManagement = true\r
+\r
+# Run the webapp in debug mode\r
+web.debugMode = false\r
+\r
+# Enable/disable global regex substitutions (i.e. shared across repositories)\r
+regex.global = true\r
+\r
+# Example global regex substitutions\r
+# Use !!! to separate the search pattern and the replace pattern\r
+# searchpattern!!!replacepattern\r
+#regex.global.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!<a href="http://somehost/bug/$3">Bug-Id: $3</a>\r
+#regex.global.changeid = \\b(Change-Id:\\s*)([A-Za-z0-9]*)\\b!!!<a href="http://somehost/changeid/$2">Change-Id: $2</a>\r
+\r
+# Example per-repository regex substitutions overrides global\r
+#regex.myrepository.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!<a href="http://elsewhere/bug/$3">Bug-Id: $3</a>\r
+\r
+#\r
+# Server Settings\r
+#\r
+server.tempFolder = temp\r
+server.log4jPattern = %-5p %d{MM-dd HH:mm:ss.SSS}  %-20.20c{1}  %m%n\r
+server.log4jPattern.windows = %-5p %m%n\r
+server.log4jPattern.linux =\r
+\r
+\r
+#\r
+# Jetty Settings\r
+#\r
+\r
+# Use Jetty NIO connectors.  If false, Jetty Socket connectors will be used.\r
+server.useNio = true\r
+\r
+# Standard http port to serve.  <= 0 disables this connector.\r
+server.httpPort = 0\r
+\r
+# Secure/SSL https port to serve. <= 0 disables this connector.\r
+server.httpsPort = 443\r
+\r
+# Specify the interface for Jetty to bind the standard connector.\r
+# You may specify an ip or an empty value to bind to all interfaces. \r
+server.httpBindInterface = localhost\r
+\r
+# Specify the interface for Jetty to bind the secure connector.\r
+# You may specify an ip or an empty value to bind to all interfaces.\r
+server.httpsBindInterface = localhost\r
+\r
+# Password for SSL keystore.\r
+# Keystore password and certificate password must match.\r
+# This is provided for convenience, its probably more secure to set this value\r
+# using the --storePassword command line parameter.\r
+server.storePassword = dosomegit\r
+\r
+# Port for shutdown monitor to listen on.\r
+server.shutdownPort = 8081\r
diff --git a/distrib/installService.bat b/distrib/installService.bat
new file mode 100644 (file)
index 0000000..5b0df2c
--- /dev/null
@@ -0,0 +1,2 @@
+set JDK=C:\Program Files\Java\jdk1.6.0_21\r
+JavaService.exe -install gitblit "%JDK%\jre\bin\server\jvm.dll" -Xmx1024M -Djava.class.path=%CD%\gitblit.jar;"%JDK%\lib\tools.jar" -start com.gitblit.Launcher -params --storePassword dosomegit -stop com.gitblit.Launcher -params --stop -out %CD%\logs\stdout.log -err %CD%\logs\stderr.log -current %CD%
\ No newline at end of file
diff --git a/distrib/installService64.bat b/distrib/installService64.bat
new file mode 100644 (file)
index 0000000..08761f8
--- /dev/null
@@ -0,0 +1,2 @@
+set JDK=C:\Program Files\Java\jdk1.6.0_21\r
+JavaService64.exe -install gitblit "%JDK%\jre\bin\server\jvm.dll" -Djava.class.path=%CD%\gitblit.jar;"%JDK%\lib\tools.jar" -start com.gitblit.Launcher -params --storePassword dosomegit -stop com.gitblit.Launcher -params --stop -out %CD%\logs\stdout.log -err %CD%\logs\stderr.log -current %CD%
\ No newline at end of file
diff --git a/distrib/makekeystore_jdk.cmd b/distrib/makekeystore_jdk.cmd
new file mode 100644 (file)
index 0000000..34a11b2
--- /dev/null
@@ -0,0 +1,2 @@
+@del keystore\r
+@keytool -keystore keystore -alias localhost -genkey -keyalg RSA -dname "CN=localhost, OU=Git:Blit, O=Git:Blit, L=Some Town, ST=Some State, C=US"
\ No newline at end of file
diff --git a/distrib/users.properties b/distrib/users.properties
new file mode 100644 (file)
index 0000000..920f323
--- /dev/null
@@ -0,0 +1,2 @@
+# Git:Blit realm file format: username=password,\#permission,repository1,repository2...\r
+admin=admin,\#admin\r
index 2bdcf2c86e70920460507a18a8bcb0a10712d21c..b9aae7cf0c2ceda11fb4b3919e9ff1fa5ae06ca3 100644 (file)
@@ -31,7 +31,11 @@ web.authenticateViewPages = false
 web.authenticateAdminPages = true\r
 \r
 # Simple user realm file to authenticate users\r
-server.realmFile = users.properties\r
+realm.realmFile = users.properties\r
+\r
+# How to store passwords.\r
+# Valid values are plain, md5 or crypt (unix style).  Default is md5. \r
+realm.passwordStorage = md5\r
 \r
 #\r
 # Git:Blit Web Settings\r
diff --git a/service/JavaService.exe b/service/JavaService.exe
deleted file mode 100644 (file)
index 8755955..0000000
Binary files a/service/JavaService.exe and /dev/null differ
diff --git a/service/JavaService64.exe b/service/JavaService64.exe
deleted file mode 100644 (file)
index fb32708..0000000
Binary files a/service/JavaService64.exe and /dev/null differ
diff --git a/service/UninstallService.bat b/service/UninstallService.bat
deleted file mode 100644 (file)
index a483c55..0000000
+++ /dev/null
@@ -1 +0,0 @@
-javaservice -uninstall gitblit
\ No newline at end of file
diff --git a/service/UninstallService64.bat b/service/UninstallService64.bat
deleted file mode 100644 (file)
index 91f0c84..0000000
+++ /dev/null
@@ -1 +0,0 @@
-javaservice64 -uninstall gitblit
\ No newline at end of file
diff --git a/service/installService.bat b/service/installService.bat
deleted file mode 100644 (file)
index 5b0df2c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-set JDK=C:\Program Files\Java\jdk1.6.0_21\r
-JavaService.exe -install gitblit "%JDK%\jre\bin\server\jvm.dll" -Xmx1024M -Djava.class.path=%CD%\gitblit.jar;"%JDK%\lib\tools.jar" -start com.gitblit.Launcher -params --storePassword dosomegit -stop com.gitblit.Launcher -params --stop -out %CD%\logs\stdout.log -err %CD%\logs\stderr.log -current %CD%
\ No newline at end of file
diff --git a/service/installService64.bat b/service/installService64.bat
deleted file mode 100644 (file)
index 08761f8..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-set JDK=C:\Program Files\Java\jdk1.6.0_21\r
-JavaService64.exe -install gitblit "%JDK%\jre\bin\server\jvm.dll" -Djava.class.path=%CD%\gitblit.jar;"%JDK%\lib\tools.jar" -start com.gitblit.Launcher -params --storePassword dosomegit -stop com.gitblit.Launcher -params --stop -out %CD%\logs\stdout.log -err %CD%\logs\stderr.log -current %CD%
\ No newline at end of file
index 7d1758db27e47e8c5e2ddca84cb4183011cdaea7..1b4a5188e59e6e8159c0786ddc8cf58a63cf48b0 100644 (file)
@@ -4,6 +4,8 @@ public class Constants {
 \r
        public final static String NAME = "Git:Blit";\r
 \r
+       // The build script extracts this exact line so be careful editing it\r
+       // and only use A-Z a-z 0-9 .-_ in the string. \r
        public final static String VERSION = "0.1.0-SNAPSHOT";\r
 \r
        public final static String ADMIN_ROLE = "#admin";\r
@@ -21,23 +23,17 @@ public class Constants {
                        }\r
                        return NONE;\r
                }\r
-               \r
+\r
+               public boolean exceeds(AccessRestrictionType type) {\r
+                       return this.ordinal() > type.ordinal();\r
+               }\r
+\r
                public boolean atLeast(AccessRestrictionType type) {\r
                        return this.ordinal() >= type.ordinal();\r
                }\r
 \r
                public String toString() {\r
-                       switch (this) {\r
-                       case NONE:\r
-                               return "Anonymous View, Clone, & Push";\r
-                       case PUSH:\r
-                               return "Anonymous View & Clone, Authenticated Push";\r
-                       case CLONE:\r
-                               return "Anonymous View, Authenticated Clone & Push";\r
-                       case VIEW:\r
-                               return "Authenticated View, Clone, & Push";\r
-                       }\r
-                       return "none";\r
+                       return name();\r
                }\r
        }\r
 \r
index 40cb3886137836185575c880bf99ea44121e7414..62ff55ebeb251f3c28f7ab4a954be3233e1b0224 100644 (file)
@@ -95,11 +95,23 @@ public class GitBlit implements ServletContextListener {
                userCookie.setPath("/");\r
                response.addCookie(userCookie);\r
        }\r
+       \r
+       public List<String> getAllUsernames() {\r
+               return loginService.getAllUsernames();\r
+       }\r
 \r
-       public UserModel getUser(String username) {\r
+       public UserModel getUserModel(String username) {\r
                UserModel user = loginService.getUserModel(username);\r
                return user;\r
        }\r
+       \r
+       public List<String> getRepositoryUsers(RepositoryModel repository) {\r
+               return loginService.getUsernamesForRole(repository.name);\r
+       }\r
+       \r
+       public boolean setRepositoryUsers(RepositoryModel repository, List<String> repositoryUsers) {\r
+               return loginService.setUsernamesForRole(repository.name, repositoryUsers);\r
+       }\r
 \r
        public void editUserModel(UserModel user, boolean isCreate) throws GitBlitException {\r
                if (!loginService.updateUserModel(user)) {\r
@@ -206,7 +218,7 @@ public class GitBlit implements ServletContextListener {
        }\r
 \r
        public void configureContext(IStoredSettings settings) {\r
-               logger.info("Configure GitBlit from " + settings.toString());\r
+               logger.info("Using configuration from " + settings.toString());\r
                this.storedSettings = settings;\r
                repositoriesFolder = new File(settings.getString(Keys.git.repositoriesFolder, "repos"));\r
                exportAll = settings.getBoolean(Keys.git.exportAll, true);\r
index f5ed91aa4857ffc49d418633d04da6c8e4177df1..17b9e7a006b375b02b9ea1c25f7d0aada579994d 100644 (file)
@@ -458,7 +458,7 @@ public class GitBlitServer {
                 * Authentication Parameters\r
                 */\r
                @Parameter(names = { "--realmFile" }, description = "Users Realm Hash File")\r
-               public String realmFile = fileSettings.getString(Keys.server.realmFile, "users.properties");\r
+               public String realmFile = fileSettings.getString(Keys.realm.realmFile, "users.properties");\r
 \r
                /*\r
                 * JETTY Parameters\r
index d0c5d13d856177d3a535574ded404999abe69ebe..242ff803af61f4b5bc7f1957bbd5ee81f2ce63f0 100644 (file)
@@ -1,5 +1,7 @@
 package com.gitblit;\r
 \r
+import java.util.List;\r
+\r
 import com.gitblit.wicket.models.UserModel;\r
 \r
 public interface ILoginService {\r
@@ -14,4 +16,14 @@ public interface ILoginService {
        \r
        boolean deleteUserModel(UserModel model);\r
        \r
+       List<String> getAllUsernames();\r
+       \r
+       List<String> getUsernamesForRole(String role);\r
+       \r
+       boolean setUsernamesForRole(String role, List<String> usernames);\r
+       \r
+       boolean renameRole(String oldRole, String newRole);\r
+       \r
+       boolean deleteRole(String role);\r
+       \r
 }\r
index 4b439647e21a962d78c76d9cf485506e8e68cd68..fb510ee6f4f4b42da29fb2e7e4a73e1dfa35377d 100644 (file)
@@ -5,9 +5,13 @@ import java.io.FileReader;
 import java.io.FileWriter;\r
 import java.io.IOException;\r
 import java.security.Principal;\r
+import java.text.MessageFormat;\r
 import java.util.ArrayList;\r
+import java.util.HashSet;\r
+import java.util.List;\r
 import java.util.Map;\r
 import java.util.Properties;\r
+import java.util.Set;\r
 \r
 import javax.security.auth.Subject;\r
 \r
@@ -16,12 +20,16 @@ import org.eclipse.jetty.security.IdentityService;
 import org.eclipse.jetty.security.MappedLoginService;\r
 import org.eclipse.jetty.server.UserIdentity;\r
 import org.eclipse.jetty.util.log.Log;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
 \r
 import com.gitblit.utils.StringUtils;\r
 import com.gitblit.wicket.models.UserModel;\r
 \r
 public class JettyLoginService extends MappedLoginService implements ILoginService {\r
 \r
+       private final Logger logger = LoggerFactory.getLogger(JettyLoginService.class);\r
+\r
        private final File realmFile;\r
 \r
        public JettyLoginService(File realmFile) {\r
@@ -44,8 +52,9 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi
                for (Principal principal : identity.getSubject().getPrincipals()) {\r
                        if (principal instanceof RolePrincipal) {\r
                                RolePrincipal role = (RolePrincipal) principal;\r
-                               if (role.getName().charAt(0) != '#') {\r
-                                       user.addRepository(role.getName().substring(1));\r
+                               String roleName = role.getName();\r
+                               if (roleName.charAt(0) != '#') {\r
+                                       user.addRepository(roleName);\r
                                }\r
                        }\r
                }\r
@@ -75,25 +84,29 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi
                                        }\r
                                        break;\r
                                default:\r
-                                       model.addRepository(name.substring(1));\r
+                                       model.addRepository(name);\r
                                }\r
                        }\r
                }\r
+               // Retrieve the password from the realm file.\r
+               // Stupid, I know, but the password is buried within protected inner\r
+               // classes in private variables. Too much work to reflectively retrieve.\r
+               try {\r
+                       Properties allUsers = readRealmFile();\r
+                       String value = allUsers.getProperty(username);\r
+                       String password = value.split(",")[0];\r
+                       model.setPassword(password);\r
+               } catch (Throwable t) {\r
+                       logger.error(MessageFormat.format("Failed to read password for user {0}!", username), t);\r
+               }\r
                return model;\r
        }\r
 \r
        @Override\r
        public boolean updateUserModel(UserModel model) {\r
                try {\r
-                       Properties properties = new Properties();\r
-                       FileReader reader = new FileReader(realmFile);\r
-                       properties.load(reader);\r
-                       reader.close();\r
-\r
-                       ArrayList<String> roles = new ArrayList<String>();\r
-\r
-                       // Repositories\r
-                       roles.addAll(model.getRepositories());\r
+                       Properties allUsers = readRealmFile();\r
+                       ArrayList<String> roles = new ArrayList<String>(model.getRepositories());\r
 \r
                        // Permissions\r
                        if (model.canAdmin()) {\r
@@ -109,21 +122,15 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi
                        }\r
                        // trim trailing comma\r
                        sb.setLength(sb.length() - 1);\r
+                       allUsers.put(model.getUsername(), sb.toString());\r
 \r
-                       // Update realm file\r
-                       File realmFileCopy = new File(realmFile.getAbsolutePath() + ".tmp");\r
-                       FileWriter writer = new FileWriter(realmFileCopy);\r
-                       properties.put(model.getUsername(), sb.toString());\r
-                       properties.store(writer, null);\r
-                       writer.close();\r
-                       realmFile.delete();\r
-                       realmFileCopy.renameTo(realmFile);\r
+                       writeRealmFile(allUsers);\r
 \r
                        // Update login service\r
                        putUser(model.getUsername(), Credential.getCredential(model.getPassword()), roles.toArray(new String[0]));\r
                        return true;\r
                } catch (Throwable t) {\r
-                       t.printStackTrace();\r
+                       logger.error(MessageFormat.format("Failed to update user model {0}!", model.getUsername()), t);\r
                }\r
                return false;\r
        }\r
@@ -132,29 +139,258 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi
        public boolean deleteUserModel(UserModel model) {\r
                try {\r
                        // Read realm file\r
-                       Properties properties = new Properties();\r
-                       FileReader reader = new FileReader(realmFile);\r
-                       properties.load(reader);\r
-                       reader.close();\r
-                       properties.remove(model.getUsername());\r
-\r
-                       // Update realm file\r
-                       File realmFileCopy = new File(realmFile.getAbsolutePath() + ".tmp");\r
-                       FileWriter writer = new FileWriter(realmFileCopy);\r
-                       properties.store(writer, null);\r
-                       writer.close();\r
-                       realmFile.delete();\r
-                       realmFileCopy.renameTo(realmFile);\r
+                       Properties allUsers = readRealmFile();\r
+                       allUsers.remove(model.getUsername());\r
+                       writeRealmFile(allUsers);\r
 \r
                        // Drop user from map\r
                        _users.remove(model.getUsername());\r
                        return true;\r
                } catch (Throwable t) {\r
-                       t.printStackTrace();\r
+                       logger.error(MessageFormat.format("Failed to delete user model {0}!", model.getUsername()), t);\r
+               }\r
+               return false;\r
+       }\r
+\r
+       @Override\r
+       public List<String> getAllUsernames() {\r
+               List<String> list = new ArrayList<String>();\r
+               list.addAll(_users.keySet());\r
+               return list;\r
+       }\r
+\r
+       @Override\r
+       public List<String> getUsernamesForRole(String role) {\r
+               List<String> list = new ArrayList<String>();\r
+               try {\r
+                       Properties allUsers = readRealmFile();\r
+                       for (String username : allUsers.stringPropertyNames()) {\r
+                               String value = allUsers.getProperty(username);\r
+                               String[] values = value.split(",");\r
+                               // skip first value (password)\r
+                               for (int i = 1; i < values.length; i++) {\r
+                                       String r = values[i];\r
+                                       if (r.equalsIgnoreCase(role)) {\r
+                                               list.add(username);\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+               } catch (Throwable t) {\r
+                       logger.error(MessageFormat.format("Failed to get usernames for role {0}!", role), t);\r
+               }\r
+               return list;\r
+       }\r
+\r
+       @Override\r
+       public boolean setUsernamesForRole(String role, List<String> usernames) {\r
+               try {\r
+                       Set<String> specifiedUsers = new HashSet<String>(usernames);\r
+                       Set<String> needsAddRole = new HashSet<String>(specifiedUsers);\r
+                       Set<String> needsRemoveRole = new HashSet<String>();\r
+\r
+                       // identify users which require add and remove role\r
+                       Properties allUsers = readRealmFile();\r
+                       for (String username : allUsers.stringPropertyNames()) {\r
+                               String value = allUsers.getProperty(username);\r
+                               String[] values = value.split(",");\r
+                               // skip first value (password)\r
+                               for (int i = 1; i < values.length; i++) {\r
+                                       String r = values[i];\r
+                                       if (r.equalsIgnoreCase(role)) {\r
+                                               // user has role, check against revised user list\r
+                                               if (specifiedUsers.contains(username)) {\r
+                                                       needsAddRole.remove(username);\r
+                                               } else {\r
+                                                       // remove role from user\r
+                                                       needsRemoveRole.add(username);\r
+                                               }\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       // add roles to users\r
+                       for (String user : needsAddRole) {\r
+                               String userValues = allUsers.getProperty(user);\r
+                               userValues += ("," + role);\r
+                               allUsers.put(user, userValues);\r
+                               String[] values = userValues.split(",");\r
+                               String password = values[0];\r
+                               String[] roles = new String[values.length - 1];\r
+                               System.arraycopy(values, 1, roles, 0, values.length - 1);\r
+                               putUser(user, Credential.getCredential(password), roles);\r
+                       }\r
+\r
+                       // remove role from user\r
+                       for (String user : needsRemoveRole) {\r
+                               String[] values = allUsers.getProperty(user).split(",");\r
+                               String password = values[0];\r
+                               StringBuilder sb = new StringBuilder();\r
+                               sb.append(password);\r
+                               sb.append(',');\r
+                               List<String> revisedRoles = new ArrayList<String>();\r
+                               // skip first value (password)\r
+                               for (int i = 1; i < values.length; i++) {\r
+                                       String value = values[i];\r
+                                       if (!value.equalsIgnoreCase(role)) {\r
+                                               revisedRoles.add(value);\r
+                                               sb.append(value);\r
+                                               sb.append(',');\r
+                                       }\r
+                               }\r
+                               sb.setLength(sb.length() - 1);\r
+\r
+                               // update properties\r
+                               allUsers.put(user, sb.toString());\r
+\r
+                               // update memory\r
+                               putUser(user, Credential.getCredential(password), revisedRoles.toArray(new String[0]));\r
+                       }\r
+\r
+                       // persist changes\r
+                       writeRealmFile(allUsers);\r
+                       return true;\r
+               } catch (Throwable t) {\r
+                       logger.error(MessageFormat.format("Failed to set usernames for role {0}!", role), t);\r
+               }\r
+               return false;\r
+       }\r
+\r
+       @Override\r
+       public boolean renameRole(String oldRole, String newRole) {\r
+               try {\r
+                       Properties allUsers = readRealmFile();\r
+                       Set<String> needsRenameRole = new HashSet<String>();\r
+\r
+                       // identify users which require role rename\r
+                       for (String username : allUsers.stringPropertyNames()) {\r
+                               String value = allUsers.getProperty(username);\r
+                               String[] roles = value.split(",");\r
+                               // skip first value (password)\r
+                               for (int i = 1; i < roles.length; i++) {\r
+                                       String r = roles[i];\r
+                                       if (r.equalsIgnoreCase(oldRole)) {\r
+                                               needsRenameRole.remove(username);\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       // rename role for identified users\r
+                       for (String user : needsRenameRole) {\r
+                               String userValues = allUsers.getProperty(user);\r
+                               String[] values = userValues.split(",");\r
+                               String password = values[0];\r
+                               StringBuilder sb = new StringBuilder();\r
+                               sb.append(password);\r
+                               sb.append(',');\r
+                               List<String> revisedRoles = new ArrayList<String>();\r
+                               revisedRoles.add(newRole);\r
+                               // skip first value (password)\r
+                               for (int i = 1; i < values.length; i++) {\r
+                                       String value = values[i];\r
+                                       if (!value.equalsIgnoreCase(oldRole)) {\r
+                                               revisedRoles.add(value);\r
+                                               sb.append(value);\r
+                                               sb.append(',');\r
+                                       }\r
+                               }\r
+                               sb.setLength(sb.length() - 1);\r
+\r
+                               // update properties\r
+                               allUsers.put(user, sb.toString());\r
+\r
+                               // update memory\r
+                               putUser(user, Credential.getCredential(password), revisedRoles.toArray(new String[0]));\r
+                       }\r
+\r
+                       // persist changes\r
+                       writeRealmFile(allUsers);\r
+                       return true;\r
+               } catch (Throwable t) {\r
+                       logger.error(MessageFormat.format("Failed to rename role {0} to {1}!", oldRole, newRole), t);\r
                }\r
                return false;\r
        }\r
 \r
+       @Override\r
+       public boolean deleteRole(String role) {\r
+               try {\r
+                       Properties allUsers = readRealmFile();\r
+                       Set<String> needsDeleteRole = new HashSet<String>();\r
+\r
+                       // identify users which require role rename\r
+                       for (String username : allUsers.stringPropertyNames()) {\r
+                               String value = allUsers.getProperty(username);\r
+                               String[] roles = value.split(",");\r
+                               // skip first value (password)\r
+                               for (int i = 1; i < roles.length; i++) {\r
+                                       String r = roles[i];\r
+                                       if (r.equalsIgnoreCase(role)) {\r
+                                               needsDeleteRole.remove(username);\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       // delete role for identified users\r
+                       for (String user : needsDeleteRole) {\r
+                               String userValues = allUsers.getProperty(user);\r
+                               String[] values = userValues.split(",");\r
+                               String password = values[0];\r
+                               StringBuilder sb = new StringBuilder();\r
+                               sb.append(password);\r
+                               sb.append(',');\r
+                               List<String> revisedRoles = new ArrayList<String>();\r
+                               // skip first value (password)\r
+                               for (int i = 1; i < values.length; i++) {\r
+                                       String value = values[i];\r
+                                       if (!value.equalsIgnoreCase(role)) {\r
+                                               revisedRoles.add(value);\r
+                                               sb.append(value);\r
+                                               sb.append(',');\r
+                                       }\r
+                               }\r
+                               sb.setLength(sb.length() - 1);\r
+\r
+                               // update properties\r
+                               allUsers.put(user, sb.toString());\r
+\r
+                               // update memory\r
+                               putUser(user, Credential.getCredential(password), revisedRoles.toArray(new String[0]));\r
+                       }\r
+\r
+                       // persist changes\r
+                       writeRealmFile(allUsers);\r
+               } catch (Throwable t) {\r
+                       logger.error(MessageFormat.format("Failed to delete role {0}!", role), t);\r
+               }\r
+               return false;\r
+       }\r
+\r
+       private Properties readRealmFile() throws IOException {\r
+               Properties allUsers = new Properties();\r
+               FileReader reader = new FileReader(realmFile);\r
+               allUsers.load(reader);\r
+               reader.close();\r
+               return allUsers;\r
+       }\r
+\r
+       private void writeRealmFile(Properties properties) throws IOException {\r
+               // Update realm file\r
+               File realmFileCopy = new File(realmFile.getAbsolutePath() + ".tmp");\r
+               FileWriter writer = new FileWriter(realmFileCopy);\r
+               properties.store(writer, "# Git:Blit realm file format: username=password,\\#permission,repository1,repository2...");\r
+               writer.close();\r
+               if (realmFileCopy.exists() && realmFileCopy.length() > 0) {\r
+                       realmFile.delete();\r
+                       realmFileCopy.renameTo(realmFile);\r
+               } else {\r
+                       throw new IOException("Failed to save realmfile!");\r
+               }\r
+       }\r
+\r
        /* ------------------------------------------------------------ */\r
        @Override\r
        public void loadUsers() throws IOException {\r
@@ -163,13 +399,10 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi
 \r
                if (Log.isDebugEnabled())\r
                        Log.debug("Load " + this + " from " + realmFile);\r
-               Properties properties = new Properties();\r
-               FileReader reader = new FileReader(realmFile);\r
-               properties.load(reader);\r
-               reader.close();\r
+               Properties allUsers = readRealmFile();\r
 \r
                // Map Users\r
-               for (Map.Entry<Object, Object> entry : properties.entrySet()) {\r
+               for (Map.Entry<Object, Object> entry : allUsers.entrySet()) {\r
                        String username = ((String) entry.getKey()).trim();\r
                        String credentials = ((String) entry.getValue()).trim();\r
                        String roles = null;\r
index 6125f2a0620d3fe90250d2df966a5499524b3609..733f4f7a5d4e2e9158d3441bf96aee1ef7d574b6 100644 (file)
@@ -1,5 +1,7 @@
 package com.gitblit.wicket;\r
 \r
+import java.util.LinkedHashMap;\r
+import java.util.Map;\r
 import java.util.TimeZone;\r
 \r
 import javax.servlet.http.HttpServletRequest;\r
@@ -14,6 +16,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;\r
 \r
 import com.gitblit.Constants;\r
+import com.gitblit.Constants.AccessRestrictionType;\r
 import com.gitblit.GitBlit;\r
 import com.gitblit.Keys;\r
 import com.gitblit.wicket.pages.SummaryPage;\r
@@ -68,6 +71,27 @@ public abstract class BasePage extends WebPage {
                }\r
        }\r
 \r
+       protected Map<AccessRestrictionType, String> getAccessRestrictions() {\r
+               Map<AccessRestrictionType, String> map = new LinkedHashMap<AccessRestrictionType, String>();\r
+               for (AccessRestrictionType type : AccessRestrictionType.values()) {\r
+                       switch (type) {\r
+                       case NONE:\r
+                               map.put(type, getString("gb.notRestricted"));\r
+                               break;\r
+                       case PUSH:\r
+                               map.put(type, getString("gb.pushRestricted"));\r
+                               break;\r
+                       case CLONE:\r
+                               map.put(type, getString("gb.cloneRestricted"));\r
+                               break;\r
+                       case VIEW:\r
+                               map.put(type, getString("gb.viewRestricted"));\r
+                               break;\r
+                       }\r
+               }\r
+               return map;\r
+       }\r
+\r
        protected TimeZone getTimeZone() {\r
                return GitBlit.self().settings().getBoolean(Keys.web.useClientTimezone, false) ? GitBlitWebSession.get().getTimezone() : TimeZone.getDefault();\r
        }\r
index f2fe2327ff691498435b5cff673c7c2ae6326e58..3fe24d0ab1e0fbf056cc266a15b633c98865451c 100644 (file)
@@ -80,9 +80,14 @@ gb.showRemoteBranches = show remote branches
 gb.editUsers = edit users\r
 gb.password = password\r
 gb.confirmPassword = confirm password\r
-gb.repositories = repositories\r
+gb.restrictedRepositories = restricted repositories\r
 gb.canAdmin can admin\r
-gb.notRestricted = open repository\r
-gb.cloneRestricted = clone-restricted repository\r
-gb.pushRestricted = push-restricted repository\r
-gb.viewRestricted = view-restricted repository
\ No newline at end of file
+gb.notRestricted = anonymous view, clone, & push\r
+gb.pushRestricted = authenticated push\r
+gb.cloneRestricted = authenticated clone & push\r
+gb.viewRestricted = authenticated view, clone, & push\r
+gb.useTicketsDescription = distributed Ticgit issues\r
+gb.useDocsDescription = enumerates Markdown documentation in repository\r
+gb.showRemoteBranchesDescription = show remote branches\r
+gb.canAdminDescription = can administer Git:Blit server\r
+gb.permittedUsers = permitted users
\ No newline at end of file
index 5872347586fc77afdeb03d01286b4a21f7dd336d..db5ab2297dcdac1303b68a515cc9c0c600054ef5 100644 (file)
                                <tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input type="text" wicket:id="name" id="name" size="40" tabindex="1" /></td></tr>\r
                                <tr><th><wicket:message key="gb.description"></wicket:message></th><td class="edit"><input type="text" wicket:id="description" size="40" tabindex="2" /></td></tr>\r
                                <tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><input type="text" wicket:id="owner" size="40" tabindex="3" /></td></tr>\r
-                               <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select wicket:id="accessRestriction" tabindex="4" /></td></tr>                               \r
-                               <tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useTickets" tabindex="5" /> &nbsp;<i>distributed Ticgit issues</i></td></tr>\r
-                               <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useDocs" tabindex="6" /> &nbsp;<i>enumerates Markdown documentation in repository</i></td></tr>\r
-                               <tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="7" /> &nbsp;<i>show remote branches</i></td></tr>\r
+                               <tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useTickets" tabindex="4" /> &nbsp;<i><wicket:message key="gb.useTicketsDescription"></wicket:message></i></td></tr>\r
+                               <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useDocs" tabindex="5" /> &nbsp;<i><wicket:message key="gb.useDocsDescription"></wicket:message></i></td></tr>\r
+                               <tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="6" /> &nbsp;<i><wicket:message key="gb.showRemoteBranchesDescription"></wicket:message></i></td></tr>\r
+                               <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select wicket:id="accessRestriction" tabindex="7" /></td></tr>                               \r
+                               <tr><th style="vertical-align: top;"><wicket:message key="gb.permittedUsers"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr>                           \r
                                <tr><th></th><td class="editButton"><input type="submit" value="Save" wicket:message="value:gb.save" tabindex="8" /></td></tr>\r
                        </tbody>\r
                </table>\r
index 2d2b0ae2b5e0c12b653848ed7bce7e6dc9f9c666..8eed00593cc7c57d0f416fe22b64ed0baa6c3539 100644 (file)
@@ -1,18 +1,29 @@
 package com.gitblit.wicket.pages;\r
 \r
+import java.text.MessageFormat;\r
+import java.util.ArrayList;\r
 import java.util.Arrays;\r
 import java.util.Date;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
 \r
 import org.apache.wicket.PageParameters;\r
+import org.apache.wicket.extensions.markup.html.form.palette.Palette;\r
 import org.apache.wicket.markup.html.form.CheckBox;\r
+import org.apache.wicket.markup.html.form.ChoiceRenderer;\r
 import org.apache.wicket.markup.html.form.DropDownChoice;\r
 import org.apache.wicket.markup.html.form.Form;\r
+import org.apache.wicket.markup.html.form.IChoiceRenderer;\r
 import org.apache.wicket.markup.html.form.TextField;\r
 import org.apache.wicket.model.CompoundPropertyModel;\r
+import org.apache.wicket.model.util.CollectionModel;\r
+import org.apache.wicket.model.util.ListModel;\r
 \r
 import com.gitblit.Constants.AccessRestrictionType;\r
 import com.gitblit.GitBlit;\r
 import com.gitblit.GitBlitException;\r
+import com.gitblit.utils.StringUtils;\r
 import com.gitblit.wicket.AdminPage;\r
 import com.gitblit.wicket.BasePage;\r
 import com.gitblit.wicket.WicketUtils;\r
@@ -40,11 +51,17 @@ public class EditRepositoryPage extends BasePage {
        }\r
 \r
        protected void setupPage(final RepositoryModel repositoryModel) {\r
+               List<String> repositoryUsers = new ArrayList<String>();\r
                if (isCreate) {\r
                        super.setupPage("", getString("gb.newRepository"));\r
                } else {\r
-                       super.setupPage("", getString("gb.edit") + " " + repositoryModel.name);\r
+                       super.setupPage("", getString("gb.edit"));\r
+                       if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {\r
+                               repositoryUsers.addAll(GitBlit.self().getRepositoryUsers(repositoryModel));\r
+                       }\r
                }\r
+\r
+               final Palette<String> usersPalette = new Palette<String>("users", new ListModel<String>(repositoryUsers), new CollectionModel<String>(GitBlit.self().getAllUsernames()), new ChoiceRenderer<String>("", ""), 10, false);\r
                CompoundPropertyModel<RepositoryModel> model = new CompoundPropertyModel<RepositoryModel>(repositoryModel);\r
                Form<RepositoryModel> form = new Form<RepositoryModel>("editForm", model) {\r
 \r
@@ -53,7 +70,48 @@ public class EditRepositoryPage extends BasePage {
                        @Override\r
                        protected void onSubmit() {\r
                                try {\r
+                                       // confirm a repository name was entered\r
+                                       if (StringUtils.isEmpty(repositoryModel.name)) {\r
+                                               error("Please set repository name!");\r
+                                               return;\r
+                                       }\r
+\r
+                                       // automatically convert backslashes to forward slashes\r
+                                       repositoryModel.name = repositoryModel.name.replace('\\', '/');\r
+\r
+                                       // confirm valid characters in repository name\r
+                                       char[] validChars = { '/', '.', '_', '-' };\r
+                                       for (char c : repositoryModel.name.toCharArray()) {\r
+                                               if (!Character.isLetterOrDigit(c)) {\r
+                                                       boolean ok = false;\r
+                                                       for (char vc : validChars) {\r
+                                                               ok |= c == vc;\r
+                                                       }\r
+                                                       if (!ok) {\r
+                                                               error(MessageFormat.format("Illegal character '{0}' in repository name!", c));\r
+                                                               return;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+\r
+                                       // confirm access restriction selection\r
+                                       if (repositoryModel.accessRestriction == null) {\r
+                                               error("Please select access restriction!");\r
+                                               return;\r
+                                       }\r
+                                       \r
+                                       // save the repository\r
                                        GitBlit.self().editRepositoryModel(repositoryModel, isCreate);\r
+                                       \r
+                                       // save the repository access list\r
+                                       if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {\r
+                                               Iterator<String> users = usersPalette.getSelectedChoices();\r
+                                               List<String> repositoryUsers = new ArrayList<String>();\r
+                                               while (users.hasNext()) {\r
+                                                       repositoryUsers.add(users.next());\r
+                                               }\r
+                                               GitBlit.self().setRepositoryUsers(repositoryModel, repositoryUsers);\r
+                                       }\r
                                } catch (GitBlitException e) {\r
                                        error(e.getMessage());\r
                                        return;\r
@@ -67,11 +125,33 @@ public class EditRepositoryPage extends BasePage {
                form.add(new TextField<String>("name").setEnabled(isCreate));\r
                form.add(new TextField<String>("description"));\r
                form.add(new TextField<String>("owner"));\r
-               form.add(new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays.asList(AccessRestrictionType.values())));\r
+               form.add(new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays.asList(AccessRestrictionType.values()), new AccessRestrictionRenderer()));\r
                form.add(new CheckBox("useTickets"));\r
                form.add(new CheckBox("useDocs"));\r
                form.add(new CheckBox("showRemoteBranches"));\r
+               form.add(usersPalette);\r
 \r
                add(form);\r
        }\r
+\r
+       private class AccessRestrictionRenderer implements IChoiceRenderer<AccessRestrictionType> {\r
+\r
+               private static final long serialVersionUID = 1L;\r
+\r
+               private final Map<AccessRestrictionType, String> map;\r
+\r
+               public AccessRestrictionRenderer() {\r
+                       map = getAccessRestrictions();\r
+               }\r
+\r
+               @Override\r
+               public String getDisplayValue(AccessRestrictionType type) {\r
+                       return map.get(type);\r
+               }\r
+\r
+               @Override\r
+               public String getIdValue(AccessRestrictionType type, int index) {\r
+                       return Integer.toString(index);\r
+               }\r
+       }\r
 }\r
index 57407d23f082bac494e8a258eb15a92b1184647b..c50bdbac6897d7b123f758f6b1e45ccc16218d3f 100644 (file)
@@ -18,8 +18,8 @@
                                <tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input type="text" wicket:id="username" id="username" size="30" tabindex="1" /></td></tr>\r
                                <tr><th><wicket:message key="gb.password"></wicket:message></th><td class="edit"><input type="password" wicket:id="password" size="30" tabindex="2" /></td></tr>\r
                                <tr><th><wicket:message key="gb.confirmPassword"></wicket:message></th><td class="edit"><input type="password" wicket:id="confirmPassword" size="30" tabindex="3" /></td></tr>\r
-                               <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> &nbsp;<i>can administer Git:Blit server</i></td></tr>                              \r
-                               <tr><th style="vertical-align: top;"><wicket:message key="gb.repositories"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> &nbsp;<i><wicket:message key="gb.canAdminDescription"></wicket:message></i></td></tr>                              \r
+                               <tr><th style="vertical-align: top;"><wicket:message key="gb.restrictedRepositories"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr>\r
                                <tr><th></th><td class="editButton"><input type="submit" value="Save" wicket:message="value:gb.save" tabindex="7" /></td></tr>\r
                        </tbody>\r
                </table>\r
index 250d1fdedbd14d9223835d6c25e4e1a74c45abb5..d1faa782b54ee1ba2099203d2500f2e58fd5265f 100644 (file)
@@ -15,13 +15,18 @@ import org.apache.wicket.model.CompoundPropertyModel;
 import org.apache.wicket.model.Model;\r
 import org.apache.wicket.model.util.CollectionModel;\r
 import org.apache.wicket.model.util.ListModel;\r
+import org.eclipse.jetty.http.security.Credential.Crypt;\r
 import org.eclipse.jetty.http.security.Credential.MD5;\r
 \r
+import com.gitblit.Constants.AccessRestrictionType;\r
 import com.gitblit.GitBlit;\r
 import com.gitblit.GitBlitException;\r
+import com.gitblit.Keys;\r
+import com.gitblit.utils.StringUtils;\r
 import com.gitblit.wicket.AdminPage;\r
 import com.gitblit.wicket.BasePage;\r
 import com.gitblit.wicket.WicketUtils;\r
+import com.gitblit.wicket.models.RepositoryModel;\r
 import com.gitblit.wicket.models.UserModel;\r
 \r
 @AdminPage\r
@@ -41,7 +46,7 @@ public class EditUserPage extends BasePage {
                super(params);\r
                isCreate = false;\r
                String name = WicketUtils.getUsername(params);\r
-               UserModel model = GitBlit.self().getUser(name);\r
+               UserModel model = GitBlit.self().getUserModel(name);\r
                setupPage(model);\r
        }\r
 \r
@@ -51,12 +56,17 @@ public class EditUserPage extends BasePage {
                } else {\r
                        super.setupPage("", getString("gb.edit"));\r
                }\r
-               final Model<String> confirmPassword = new Model<String>();\r
+               final Model<String> confirmPassword = new Model<String>(StringUtils.isEmpty(userModel.getPassword()) ? "" : userModel.getPassword());\r
                CompoundPropertyModel<UserModel> model = new CompoundPropertyModel<UserModel>(userModel);\r
 \r
-               List<String> repos = GitBlit.self().getRepositoryList();\r
-               repos.add(0, "*"); // all repositories wildcard\r
-               final Palette<String> repositories = new Palette<String>("repositories", new ListModel<String>(userModel.getRepositories()), new CollectionModel<String>(repos), new ChoiceRenderer<String>("", ""), 10, false);                \r
+               List<String> repos = new ArrayList<String>();\r
+               for (String repo : GitBlit.self().getRepositoryList()) {\r
+                       RepositoryModel repositoryModel = GitBlit.self().getRepositoryModel(repo);\r
+                       if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {\r
+                               repos.add(repo);\r
+                       }\r
+               }\r
+               final Palette<String> repositories = new Palette<String>("repositories", new ListModel<String>(userModel.getRepositories()), new CollectionModel<String>(repos), new ChoiceRenderer<String>("", ""), 10, false);\r
                Form<UserModel> form = new Form<UserModel>("editForm", model) {\r
 \r
                        private static final long serialVersionUID = 1L;\r
@@ -67,8 +77,20 @@ public class EditUserPage extends BasePage {
                                        error("Passwords do not match!");\r
                                        return;\r
                                }\r
-                               userModel.setPassword(MD5.digest(userModel.getPassword()));\r
-                               \r
+                               String password = userModel.getPassword();\r
+                               if (!password.toUpperCase().startsWith(Crypt.__TYPE) && !password.toUpperCase().startsWith(MD5.__TYPE)) {\r
+                                       // This is a plain text password.\r
+                                       // Optionally encrypt/obfuscate the password.\r
+                                       String type = GitBlit.self().settings().getString(Keys.realm.passwordStorage, "md5");\r
+                                       if (type.equalsIgnoreCase("md5")) {\r
+                                               // store MD5 checksum of password\r
+                                               userModel.setPassword(MD5.digest(userModel.getPassword()));\r
+                                       } else if (type.equalsIgnoreCase("crypt")) {\r
+                                               // simple unix encryption\r
+                                               userModel.setPassword(Crypt.crypt(userModel.getUsername(), userModel.getPassword()));\r
+                                       }\r
+                               }\r
+\r
                                Iterator<String> selectedRepositories = repositories.getSelectedChoices();\r
                                List<String> repos = new ArrayList<String>();\r
                                while (selectedRepositories.hasNext()) {\r
@@ -82,14 +104,24 @@ public class EditUserPage extends BasePage {
                                        return;\r
                                }\r
                                setRedirect(true);\r
-                               setResponsePage(EditUserPage.class);\r
+                               if (isCreate) {\r
+                                       // create another user\r
+                                       setResponsePage(EditUserPage.class);\r
+                               } else {\r
+                                       // back to home\r
+                                       setResponsePage(RepositoriesPage.class);\r
+                               }\r
                        }\r
                };\r
 \r
                // field names reflective match UserModel fields\r
                form.add(new TextField<String>("username").setEnabled(isCreate));\r
-               form.add(new PasswordTextField("password"));\r
-               form.add(new PasswordTextField("confirmPassword", confirmPassword));\r
+               PasswordTextField passwordField = new PasswordTextField("password");\r
+               passwordField.setResetPassword(false);\r
+               form.add(passwordField);\r
+               PasswordTextField confirmPasswordField = new PasswordTextField("confirmPassword", confirmPassword);\r
+               confirmPasswordField.setResetPassword(false);\r
+               form.add(confirmPasswordField);\r
                form.add(new CheckBox("canAdmin"));\r
                form.add(repositories);\r
                add(form);\r
index 3016f648fac45497c9c34f2be4929279afc8ab77..c33e530d18ed55b7a63371e448134a30f81e539a 100644 (file)
@@ -31,7 +31,7 @@
                        <td><div class="list" wicket:id="repositoryName">[repository name]</div></td>\r
                        <td><div class="list" wicket:id="repositoryDescription">[repository description]</div></td>\r
                        <td class="author"><span wicket:id="repositoryOwner">[repository owner]</span></td>\r
-                       <td class="icon"><img wicket:id="ticketsIcon" /><img wicket:id="docsIcon" /><img wicket:id="restrictedAccessIcon" /></td>\r
+                       <td class="icon"><img wicket:id="ticketsIcon" /><img wicket:id="docsIcon" /><img wicket:id="accessRestrictionIcon" /></td>\r
                        <td><span wicket:id="repositoryLastChange">[last change]</span></td>\r
                        <td class="rightAlign"><span wicket:id="repositoryLinks"></span></td>\r
                        </tr>\r
index 4505829694136cd2d06fdc529cdeda5c8333e470..acdc02fab67e5c92c50b2ec319b6fb8ebc023820 100644 (file)
@@ -8,6 +8,7 @@ import java.util.Collections;
 import java.util.Comparator;\r
 import java.util.Iterator;\r
 import java.util.List;\r
+import java.util.Map;\r
 \r
 import org.apache.wicket.Component;\r
 import org.apache.wicket.PageParameters;\r
@@ -23,6 +24,7 @@ import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;\r
 import org.apache.wicket.resource.ContextRelativeResource;\r
 \r
+import com.gitblit.Constants.AccessRestrictionType;\r
 import com.gitblit.GitBlit;\r
 import com.gitblit.Keys;\r
 import com.gitblit.utils.MarkdownUtils;\r
@@ -99,6 +101,7 @@ public class RepositoriesPage extends BasePage {
                }\r
                add(repositoriesMessage);\r
 \r
+               final Map<AccessRestrictionType, String> accessRestrictionTranslations = getAccessRestrictions();\r
                UserModel user = GitBlitWebSession.get().getUser();\r
                List<RepositoryModel> rows = GitBlit.self().getRepositoryModels(user);\r
                DataProvider dp = new DataProvider(rows);\r
@@ -130,22 +133,22 @@ public class RepositoriesPage extends BasePage {
                                } else {\r
                                        item.add(WicketUtils.newBlankImage("docsIcon"));\r
                                }\r
-\r
+                               \r
                                switch (entry.accessRestriction) {\r
                                case NONE:\r
-                                       item.add(WicketUtils.newBlankImage("restrictedAccessIcon"));\r
+                                       item.add(WicketUtils.newBlankImage("accessRestrictionIcon"));\r
                                        break;\r
                                case PUSH:\r
-                                       item.add(WicketUtils.newImage("restrictedAccessIcon", "lock_go_16x16.png", getString("gb.pushRestricted")));\r
+                                       item.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));\r
                                        break;\r
                                case CLONE:\r
-                                       item.add(WicketUtils.newImage("restrictedAccessIcon", "lock_pull_16x16.png", getString("gb.cloneRestricted")));\r
+                                       item.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));\r
                                        break;\r
                                case VIEW:\r
-                                       item.add(WicketUtils.newImage("restrictedAccessIcon", "shield_16x16.png", getString("gb.viewRestricted")));\r
+                                       item.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));\r
                                        break;\r
                                default:\r
-                                       item.add(WicketUtils.newBlankImage("restrictedAccessIcon"));\r
+                                       item.add(WicketUtils.newBlankImage("accessRestrictionIcon"));\r
                                }\r
 \r
                                item.add(new Label("repositoryOwner", entry.owner));\r
index 6dbcfa225744ce1315ad408569f3648defde12d6..35331f56b4181c28a15aed2eb78ea5c1fa1c0abd 100644 (file)
@@ -20,7 +20,7 @@
                                <tr><th><wicket:message key="gb.owner">[owner]</wicket:message></th><td><span wicket:id="repositoryOwner">[repository owner]</span></td></tr>\r
                                <tr><th><wicket:message key="gb.lastChange">[last change]</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>\r
                                <tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="repositoryStats">[repository stats]</span></td></tr>\r
-                               <tr><th><wicket:message key="gb.url">[URL]</wicket:message></th><td><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>\r
+                               <tr><th><wicket:message key="gb.url">[URL]</wicket:message></th><td><img style="vertical-align: top; padding-right:5px;" wicket:id="accessRestrictionIcon" /><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>\r
                        </table>\r
                </div>\r
        </div>\r
index c0193dbeec8159052fd291b032da1d37104b16ac..d83f596137b6ed8ef8066b6b6b21e5ae09310747 100644 (file)
@@ -19,6 +19,7 @@ import org.wicketstuff.googlecharts.LineStyle;
 import org.wicketstuff.googlecharts.MarkerType;\r
 import org.wicketstuff.googlecharts.ShapeMarker;\r
 \r
+import com.gitblit.Constants.AccessRestrictionType;\r
 import com.gitblit.GitBlit;\r
 import com.gitblit.Keys;\r
 import com.gitblit.utils.JGitUtils;\r
@@ -66,6 +67,24 @@ public class SummaryPage extends RepositoryPage {
                } else {\r
                        add(new Label("repositoryStats", MessageFormat.format("{0} commits and {1} tags in {2}", metricsTotal.count, metricsTotal.tag, TimeUtils.duration(metricsTotal.duration))));\r
                }\r
+               \r
+               AccessRestrictionType accessRestriction = getRepositoryModel().accessRestriction;\r
+               switch (accessRestriction) {\r
+               case NONE:\r
+                       add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));\r
+                       break;\r
+               case PUSH:\r
+                       add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png", getAccessRestrictions().get(accessRestriction)));\r
+                       break;\r
+               case CLONE:\r
+                       add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png", getAccessRestrictions().get(accessRestriction)));\r
+                       break;\r
+               case VIEW:\r
+                       add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png", getAccessRestrictions().get(accessRestriction)));\r
+                       break;\r
+               default:\r
+                       add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));\r
+               }\r
                add(new Label("repositoryCloneUrl", GitBlit.self().getCloneUrl(repositoryName)));\r
 \r
                add(new LogPanel("commitsPanel", repositoryName, null, r, numberCommits, 0));\r
index 0b22d827a5fd8a3d12cf033fb000ed06de7546ec..920f3233998835dc885b92116a3f18f6619d83d9 100644 (file)
@@ -1,3 +1,2 @@
-#Wed May 11 21:30:28 EDT 2011\r
+# Git:Blit realm file format: username=password,\#permission,repository1,repository2...\r
 admin=admin,\#admin\r
-test=test\r