diff options
author | Rafael Cavazin <rafaelcavazin@gmail.com> | 2012-12-06 14:25:01 -0200 |
---|---|---|
committer | Rafael Cavazin <rafaelcavazin@gmail.com> | 2012-12-06 14:25:01 -0200 |
commit | d4b95298902c8cea1411fc696ed80028b6091aa7 (patch) | |
tree | 1ee58f481203ef60c030a3d0119784c37a8b7b3f | |
parent | 6aea2fa8aee24114bc59b09bc3c5b68fcd948790 (diff) | |
parent | dc9735acfc9dcea6b970d18a315cbf8a6997c4f9 (diff) | |
download | gitblit-d4b95298902c8cea1411fc696ed80028b6091aa7.tar.gz gitblit-d4b95298902c8cea1411fc696ed80028b6091aa7.zip |
Update from upstream/master
Merge remote-tracking branch 'upstream/master' into translation_to_pt-br
35 files changed, 817 insertions, 325 deletions
@@ -9,8 +9,8 @@ <classpathentry kind="lib" path="ext/slf4j-log4j12-1.6.6.jar" sourcepath="ext/src/slf4j-log4j12-1.6.6-sources.jar" /> <classpathentry kind="lib" path="ext/mail-1.4.3.jar" sourcepath="ext/src/mail-1.4.3-sources.jar" /> <classpathentry kind="lib" path="ext/javax.servlet-api-3.0.1.jar" sourcepath="ext/src/javax.servlet-api-3.0.1-sources.jar" /> - <classpathentry kind="lib" path="ext/jetty-webapp-7.6.7.v20120910.jar" sourcepath="ext/src/jetty-webapp-7.6.7.v20120910-sources.jar" /> - <classpathentry kind="lib" path="ext/jetty-ajp-7.6.7.v20120910.jar" sourcepath="ext/src/jetty-ajp-7.6.7.v20120910-sources.jar" /> + <classpathentry kind="lib" path="ext/jetty-webapp-7.6.8.v20121106.jar" sourcepath="ext/src/jetty-webapp-7.6.8.v20121106-sources.jar" /> + <classpathentry kind="lib" path="ext/jetty-ajp-7.6.8.v20121106.jar" sourcepath="ext/src/jetty-ajp-7.6.8.v20121106-sources.jar" /> <classpathentry kind="lib" path="ext/wicket-1.4.21.jar" sourcepath="ext/src/wicket-1.4.21-sources.jar" /> <classpathentry kind="lib" path="ext/wicket-auth-roles-1.4.21.jar" sourcepath="ext/src/wicket-auth-roles-1.4.21-sources.jar" /> <classpathentry kind="lib" path="ext/wicket-extensions-1.4.21.jar" sourcepath="ext/src/wicket-extensions-1.4.21-sources.jar" /> @@ -20,7 +20,7 @@ <classpathentry kind="lib" path="ext/lucene-memory-3.6.1.jar" sourcepath="ext/src/lucene-memory-3.6.1-sources.jar" /> <classpathentry kind="lib" path="ext/lucene-queries-3.6.1.jar" sourcepath="ext/src/lucene-queries-3.6.1-sources.jar" /> <classpathentry kind="lib" path="ext/jakarta-regexp-1.4.jar" /> - <classpathentry kind="lib" path="ext/markdownpapers-core-1.2.7.jar" sourcepath="ext/src/markdownpapers-core-1.2.7-sources.jar" /> + <classpathentry kind="lib" path="ext/markdownpapers-core-1.3.2.jar" sourcepath="ext/src/markdownpapers-core-1.3.2-sources.jar" /> <classpathentry kind="lib" path="ext/org.eclipse.jgit-2.1.0.201209190230-r.jar" sourcepath="ext/src/org.eclipse.jgit-2.1.0.201209190230-r-sources.jar" /> <classpathentry kind="lib" path="ext/jsch-0.1.44-1.jar" sourcepath="ext/src/jsch-0.1.44-1-sources.jar" /> <classpathentry kind="lib" path="ext/org.eclipse.jgit.http.server-2.1.0.201209190230-r.jar" sourcepath="ext/src/org.eclipse.jgit.http.server-2.1.0.201209190230-r-sources.jar" /> @@ -171,7 +171,7 @@ Build Gitblit GO
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-->
- <target name="buildGO" depends="compile" description="Build Gitblit GO distribution">
+ <target name="buildGO" depends="compile,buildAuthority" description="Build Gitblit GO distribution">
<echo>Building Gitblit GO ${gb.version}</echo>
@@ -768,6 +768,7 @@ <resource file="${basedir}/resources/user_16x16.png" />
<resource file="${basedir}/resources/users_16x16.png" />
<resource file="${basedir}/resources/rosette_16x16.png" />
+ <resource file="${basedir}/resources/rosette_32x32.png" />
<resource file="${basedir}/resources/vcard_16x16.png" />
<resource file="${basedir}/resources/settings_16x16.png" />
<resource file="${basedir}/resources/settings_32x32.png" />
diff --git a/distrib/gitblit.properties b/distrib/gitblit.properties index 233fdfad..ce269d2c 100644 --- a/distrib/gitblit.properties +++ b/distrib/gitblit.properties @@ -504,6 +504,12 @@ web.compressedDownloads = zip gz # SINCE 0.9.0
web.allowLuceneIndexing = true
+# Allows an authenticated user to create forks of a repository
+#
+# set this to false if you want to disable all fork controls on the web site
+#
+web.allowForking = true
+
# Controls the length of shortened commit hash ids
#
# SINCE 1.2.0
@@ -516,6 +522,14 @@ web.shortCommitIdLength = 6 # SINCE 0.8.0
web.allowFlashCopyToClipboard = true
+# Default maximum number of commits that a repository may contribute to the
+# activity page, regardless of the selected duration. This setting may be valuable
+# for an extremely busy server. This value may also be configed per-repository
+# in Edit Repository. 0 disables this throttle.
+#
+# SINCE 1.2.0
+web.maxActivityCommits = 0
+
# Default number of entries to include in RSS Syndication links
#
# SINCE 0.5.0
@@ -1141,6 +1155,13 @@ server.httpsBindInterface = localhost # RESTART REQUIRED
server.ajpBindInterface = localhost
+# Alias of certificate to use for https/SSL serving. If blank the first
+# certificate found in the keystore will be used.
+#
+# SINCE 1.2.0
+# RESTART REQUIRED
+server.certificateAlias = localhost
+
# Password for SSL keystore.
# Keystore password and certificate password must match.
# This is provided for convenience, its probably more secure to set this value
@@ -1179,4 +1200,4 @@ server.requireClientCertificates = false #
# SINCE 0.5.0
# RESTART REQUIRED
-server.shutdownPort = 8081
\ No newline at end of file +server.shutdownPort = 8081
diff --git a/docs/01_features.mkd b/docs/01_features.mkd index ab498483..4676f755 100644 --- a/docs/01_features.mkd +++ b/docs/01_features.mkd @@ -17,7 +17,7 @@ - Optional feature to allow users to create personal repositories
- Optional feature to fork a repository to a personal repository
- Optional feature to create a repository on push
-- Experimental built-in Garbage Collection
+- *Experimental* built-in Garbage Collection
- Ability to federate with one or more other Gitblit instances
- RSS/JSON RPC interface
- Java/Swing Gitblit Manager tool
@@ -59,8 +59,8 @@ ## Gitblit GO Features
- Out-of-the-box integrated stack requiring minimal configuration
-- Automatically generates a self-signed certificate for *localhost* https communications
- (includes script to generate a self-signed certificate for *your hostname*, see [setup](/setup.html) for details)
+- Automatic generation of ssl certificate for https communications
+- Integrated GUI tool to facilitate x509 PKI including ssl and client certificate generation, client certificate revocation, and client certificate distribution
- Single text file for configuring server and gitblit
- A Windows service installation script and configuration tool
- Built-in AJP connector for Apache httpd
diff --git a/docs/01_setup.mkd b/docs/01_setup.mkd index 5c8c0066..be0e191f 100644 --- a/docs/01_setup.mkd +++ b/docs/01_setup.mkd @@ -27,7 +27,6 @@ Open `gitblit.properties` in your favorite text editor and make sure to review a - *git.repositoryFolder* (path may be relative or absolute)
- *groovy.scriptsFolder* (path may be relative or absolute)
- *groovy.grapeFolder* (path may be relative or absolute)
- - *web.siteName* (used in certificate generation, etc)
- *server.tempFolder* (path may be relative or absolute)
- *server.httpPort* and *server.httpsPort*
- *server.httpBindInterface* and *server.httpsBindInterface*
@@ -36,10 +35,10 @@ Open `gitblit.properties` in your favorite text editor and make sure to review a - *git.packedGitLimit* (set larger than the size of your largest repository)
- *git.streamFileThreshold* (set larger than the size of your largest committed file)
3. Execute `authority.cmd` or `java -jar authority.jar` from a command-line
- a. enter default values for your generated certificates in the *new certificate defaults* dialog
- b. enter the store password used in *server.storePassword* when prompted *(this generates an SSL certificate for **localhost**)*
- c. you will also want to generate SSL certificates for the hostnames or ip addresses you serve from
- d. exit the authority app
+ 1. fill out the fields in the *new certificate defaults* dialog
+ 2. enter the store password used in *server.storePassword* when prompted. This generates an SSL certificate for **localhost**.
+ 3. you may want to generate an SSL certificate for the hostname or ip address hostnames you are serving from<br/>**NOTE:** You can only have **one** SSL certificate specified for a port.
+ 5. exit the authority app
4. Execute `gitblit.cmd` or `java -jar gitblit.jar` from a command-line
5. Open your browser to <http://localhost:8080> or <https://localhost:8443> depending on your chosen configuration.
6. Enter the default administrator credentials: **admin / admin** and click the *Login* button
@@ -55,18 +54,21 @@ The EGit failure message is something like: Cannot get remote repository refs.
Reason: https:/myserver.com/git/myrepo.git: cannot open git-upload-pack
-If you want to serve your repositories to another machine over https then you will want to generate your own certificate.
+If you want to serve your repositories to another machine over https then you will want to generate a new certificate for the hostname or ip address you are serving from.
1. `authority.cmd` or `java -jar authority.jar`
2. Click the *new ssl certificate* button (red rosette in the toolbar in upper left of window)
3. Enter the hostname or ip address
-4. Enter the *server.storePassword* password
+4. Make sure the checkbox *serve https with this certificate* is checked
+5. In the keystore password prompt, enter the *server.storePassword* password
-Additionally, if you want to change the value of *server.storePassword* (recommended) you will have to delete the following files and then start the Gitblit Certificate Authority app:
+If you decide to change the value of *server.storePassword* (recommended) <u>after</u> you have already started Gitblit or Gitblit Certificate Authority, then you will have to delete the following files and then restart the Gitblit Certificate Authority app:
+
1. serverKeyStore.jks
2. serverTrustStore.jks
3. certs/caKeyStore.jks
4. certs/ca.crt
+5. certs/caRevocationList.crl (optional)
### Client SSL Certificates
SINCE 1.2.0
@@ -94,9 +96,13 @@ When you generate a new client certificate, a zip file bundle is created which i 1. `authority.cmd` or `java -jar authority.jar`
2. Select the user for which to generate the certificate
-3. Click the *new certificate* button and enter the expiration date of the certificate. You must also enter a password for the generated keystore. This password is not the same as the user's login password. This password is used to protect the privatekey and public certificate you will generate for the selected user. You must also enter a password hint for the user.
+3. Click the *new certificate* button and enter the expiration date of the certificate. You must also enter a password for the generated keystore. This password is *not* the same as the user's login password. This password is used to protect the privatekey and public certificate you will generate for the selected user. You must also enter a password hint for the user.
4. If your mail server settings are properly configured you will have a *send email* checkbox which you can use to immediately send the generated certificate bundle to the user.
+#### Certificate Inspection and Advanced Troubleshooting
+
+X509 certificates can be confusing and tricky even with the simplified Gitblit Certificate Authority tool. If you find you need more tooling to understand your keystores, certificates, and certificate revocation lists (CRLs), I highly recommend [Portecle](http://portecle.sourceforge.net) which can be conveniently launched as a [Java Web Start app](http://portecle.sourceforge.net/webstart/portecle.jnlp).
+
### Running as a Windows Service
Gitblit uses [Apache Commons Daemon](http://commons.apache.org/daemon) to install and configure its Windows service.
@@ -130,6 +136,7 @@ Command-Line parameters override the values in `gitblit.properties` at runtime. --httpPort HTTP port for to serve. (port <= 0 will disable this connector)
--httpsPort HTTPS port to serve. (port <= 0 will disable this connector)
--ajpPort AJP port to serve. (port <= 0 will disable this connector)
+ --alias Alias in keystore of SSL cert to use for https serving
--storePassword Password for SSL (https) keystore.
--shutdownPort Port for Shutdown Monitor to listen on. (port <= 0 will disable this monitor)
--tempFolder Folder for server to extract built-in webapp
diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd index 3f03160a..396b2550 100644 --- a/docs/04_releases.mkd +++ b/docs/04_releases.mkd @@ -12,6 +12,7 @@ The permissions model has changed in this release. #### fixes
+- Set subjectAlternativeName on generated SSL cert if CN is an ip address (issue 170)
- Fixed incorrect links on history page for files not in the current/active commit (issue 166)
- Empty repository page failed to handle missing repository (issue 160)
- Fixed broken ticgit urls (issue 157)
@@ -32,17 +33,18 @@ The permissions model has changed in this release. - RW (clone and push)
- RWC (clone and push with ref creation)
- RWD (clone and push with ref creation, deletion)
- - RW+ (clone and push with ref creation, deletion, rewind)
+ - RW+ (clone and push with ref creation, deletion, rewind)
While not as sophisticated as Gitolite, this does give finer access controls. These permissions fit in cleanly with the existing users.conf and users.properties files. In Gitblit <= 1.1.0, all your existing user accounts have RW+ access. If you are upgrading to 1.2.0, the RW+ access is *preserved* and you will have to lower/adjust accordingly.
- Implemented *case-insensitive* regex repository permission matching (issue 36)
This allows you to specify a permission like `RW:mygroup/.*` to grant push privileges to all repositories within the *mygroup* project/folder.
- Added DELETE, CREATE, and NON-FAST-FORWARD ref change logging
-- Added support for personal repositories.
+- Added support for personal repositories.
Personal repositories can be created by accounts with the *create* permission and are stored in *git.repositoriesFolder/~username*. Each user with personal repositories will have a user page, something like the GitHub profile page. Personal repositories have all the same features as common repositories, except personal repositories can be renamed by their owner.
- Added support for server-side forking of a repository to a personal repository (issue 137)
-In order to fork a repository, the user account must have the *fork* permission **and** the repository must *allow forks*. The clone inherits the access list of its origin. i.e. if Team A has clone access to the origin repository, then by default Team A also has clone access to the fork. This is to facilitate collaboration. The fork owner may change access to the fork and add/remove users/teams, etc as required <u>however</u> it should be noted that all personal forks will be enumerated in the fork network regardless of access view restrictions. If you really must have an invisible fork, the clone it locally, create a new repository for your invisible fork, and push it back to Gitblit.
+In order to fork a repository, the user account must have the *fork* permission **and** the repository must *allow forks*. The clone inherits the access list of its origin. i.e. if Team A has clone access to the origin repository, then by default Team A also has clone access to the fork. This is to facilitate collaboration. The fork owner may change access to the fork and add/remove users/teams, etc as required <u>however</u> it should be noted that all personal forks will be enumerated in the fork network regardless of access view restrictions. If you really must have an invisible fork, the clone it locally, create a new repository for your invisible fork, and push it back to Gitblit.
+ **New:** *web.allowForking=true*
- Added optional *create-on-push* support
- **New:** *git.allowCreateOnPush=true*
+ **New:** *git.allowCreateOnPush=true*
- Added **experimental** JGit-based garbage collection service. This service is disabled by default.
**New:** *git.allowGarbageCollection=false*
**New:** *git.garbageCollectionHour = 0*
@@ -54,12 +56,12 @@ You can require all git servlet access be authenticated by a client certificate. **New:** *git.enforceCertificateValidity = true*
**New:** *git.certificateUsernameOIDs = CN*
- Revised clean install certificate generation to create a Gitblit GO Certificate Authority certificate; an SSL certificate signed by the CA certificate; and to create distinct server key and server trust stores. <u>The store files have been renamed!</u>
-- Added support for Gitblit GO to require usage of client certificates to access the entire server.
+- Added support for Gitblit GO to require usage of client certificates to access the entire server.
This is extreme and should be considered carefully since it affects every https access. The default is to **want** client certificates. Setting this value to *true* changes that to **need** client certificates.
**New:** *server.requireClientCertificates = false*
-- Added Gitblit Certificate Authority, an X509 certificate generation tool for Gitblit GO to encourage use of client certificate authentication.
+- Added **Gitblit Certificate Authority**, an x509 PKI management tool for Gitblit GO to encourage use of x509 client certificate authentication.
- Added setting to control length of shortened commit ids
- **New:** *web.shortCommitIdLength=8*
+ **New:** *web.shortCommitIdLength=8*
- Added alternate compressed download formats: tar.gz, tar.xz, tar.bzip2 (issue 174)
**New:** *web.compressedDownloads = zip gz*
- Added simple project pages. A project is a subfolder off the *git.repositoriesFolder*.
@@ -72,7 +74,10 @@ This is extreme and should be considered carefully since it affects every https #### changes
-- Access restricted servlets (e.g. DownloadZip, RSS, etc) will try to authenticate any Gitblit cookie found in the request before resorting to BASIC authentication.
+- Added server setting to specify keystore alias for ssl certificate (issue 98)
+- Added optional global and per-repository activity page commit contribution throttle to help tame *really* active repositories (issue 173)
+- Added support for symlinks in tree page and commit page (issue 171)
+- All access restricted servlets (e.g. DownloadZip, RSS, etc) will try to authenticate using X509 certificates, container principals, cookies, and BASIC headers, in that order.
- Added *groovy* and *scala* to *web.prettyPrintExtensions*
- Added short commit id column to log and history tables (issue 168)
- Teams can now specify the *admin*, *create*, and *fork* roles to simplify user administration
@@ -83,15 +88,17 @@ This is extreme and should be considered carefully since it affects every https - Emit a warning in the log file if running on a Tomcat-based servlet container which is unfriendly to %2F forward-slash url encoding AND Gitblit is configured to mount parameters with %2F forward-slash url encoding (Github/jpyeron, issue 126)
- LDAP admin attribute setting is now consistent with LDAP teams setting and admin teams list.
If *realm.ldap.maintainTeams==true* **AND** *realm.ldap.admins* is not empty, then User.canAdmin() is controlled by LDAP administrative team membership. Otherwise, User.canAdmin() is controlled by Gitblit.
+- Support servlet container authentication for existing UserModels (issue 68)
#### dependency changes
-- updated to Jetty 7.6.7
+- updated to Jetty 7.6.8
- updated to JGit 2.1.0.201209190230-r
- updated to Groovy 1.8.8
- updated to Wicket 1.4.21
- updated to Lucene 3.6.1
- updated to BouncyCastle 1.47
+- updated to MarkdownPapers 1.3.2
- added JCalendar 1.3.2
- added Commons-Compress 1.4.1
- added XZ for Java 1.0
@@ -113,8 +120,8 @@ If you are updating from an earlier release AND you have indexed branches with t - Fixed generated urls in Groovy *sendmail* hook script for grouped repositories
- Fixed generated urls in RSS feeds for grouped repositories
- Fixed nullpointer exception in git servlet security filter (issue 123)
-- Eliminated an unnecessary repository enumeration call on the root page which should result in faster page loads (issue 103)
-- Gitblit could not delete a Lucene index in a working copy on index upgrade
+- Eliminated an unnecessary repository enumeration call on the root page which should result in faster page loads (issue 103)
+- Gitblit could not delete a Lucene index in a working copy on index upgrade
- Do not index submodule links (issue 119)
- Restore original user or team object on failure to update (issue 118)
- Fixes to relative path determination in repository search algorithm for symlinks (issue 116)
@@ -128,25 +135,25 @@ If you are updating from an earlier release AND you have indexed branches with t #### additions
-- Identified repository list is now cached by default to reduce disk io and to improve performance (issue 103)
+- Identified repository list is now cached by default to reduce disk io and to improve performance (issue 103)
**New:** *git.cacheRepositoryList=true*
-- Preliminary bare repository submodule support
+- Preliminary bare repository submodule support
**New:** *git.submoduleUrlPatterns=*
- - *git.submoduleUrlPatterns* is a space-delimited list of regular expressions for extracting a repository name from a submodule url.
- For example, `git.submoduleUrlPatterns = .*?://github.com/(.*)` would extract *gitblit/gitblit.git* from *git://github.git/gitblit/gitblit.git*
+ - *git.submoduleUrlPatterns* is a space-delimited list of regular expressions for extracting a repository name from a submodule url.
+ For example, `git.submoduleUrlPatterns = .*?://github.com/(.*)` would extract *gitblit/gitblit.git* from *git://github.git/gitblit/gitblit.git*
**Note:** You may not need this control to work with submodules, but it is there if you do.
- If there are no matches from *git.submoduleUrlPatterns* then the repository name is assumed to be whatever comes after the last `/` character *(e.g. gitblit.git)*
- Gitblit will try to locate this repository relative to the current repository *(e.g. myfolder/myrepo.git, myfolder/mysubmodule.git)* and then at the root level *(mysubmodule.git)* if that fails.
- Submodule references in a working copy will be properly identified as gitlinks, but Gitblit will not traverse into the working copy submodule repository.
-- Added a repository setting to control authorization as AUTHENTICATED or NAMED. (issue 117)
-NAMED is the original behavior for authorizing against a list of permitted users or permitted teams.
+- Added a repository setting to control authorization as AUTHENTICATED or NAMED. (issue 117)
+NAMED is the original behavior for authorizing against a list of permitted users or permitted teams.
AUTHENTICATED allows restricted access for any authenticated user. This is a looser authorization control.
-- Added default authorization control setting (AUTHENTICATED or NAMED)
- **New:** *git.defaultAuthorizationControl=NAMED*
-- Added setting to control how deep Gitblit will recurse into *git.repositoriesFolder* looking for repositories (issue 103)
- **New:** *git.searchRecursionDepth=-1*
-- Added setting to specify regex exclusions for repositories (issue 103)
- **New:** *git.searchExclusions=*
+- Added default authorization control setting (AUTHENTICATED or NAMED)
+ **New:** *git.defaultAuthorizationControl=NAMED*
+- Added setting to control how deep Gitblit will recurse into *git.repositoriesFolder* looking for repositories (issue 103)
+ **New:** *git.searchRecursionDepth=-1*
+- Added setting to specify regex exclusions for repositories (issue 103)
+ **New:** *git.searchExclusions=*
- Blob page now supports displaying images (issue 6)
- Non-image binary files can now be downloaded using the RAW link
- Support StartTLS in LdapUserService (Steffen Gebert, issue 122)
@@ -175,38 +182,38 @@ AUTHENTICATED allows restricted access for any authenticated user. This is a lo #### changes
-- **Updated Lucene index version which will force a rebuild of ALL your Lucene indexes**
+- **Updated Lucene index version which will force a rebuild of ALL your Lucene indexes**
Make sure to properly set *web.blobEncodings* before starting Gitblit if you are updating! (issue 97)
-- Changed default layout for web ui from Fixed-Width layout to Responsive layout (issue 101)
-- IUserService interface has changed to better accomodate custom authentication and/or custom authorization
- The default `users.conf` now supports persisting display names and email addresses.
+- Changed default layout for web ui from Fixed-Width layout to Responsive layout (issue 101)
+- IUserService interface has changed to better accomodate custom authentication and/or custom authorization
+ The default `users.conf` now supports persisting display names and email addresses.
- Updated Japanese translation (Github/zakki)
#### additions
-- Added setting to allow specification of a robots.txt file (issue 99)
- **New:** *web.robots.txt =*
-- Added setting to control Responsive layout or Fixed-Width layout (issue 101)
- Responsive layout is now the default. This layout gracefully scales the web ui from a desktop layout to a mobile layout by hiding page components. It is easy to try, just resize your browser or point your Android/iOS device to the url of your Gitblit install.
- **New:** *web.useResponsiveLayout = true*
-- Added setting to control charsets for blob string decoding. Default encodings are UTF-8, ISO-8859-1, and server's default charset. (issue 97)
- **New:** *web.blobEncodings = UTF-8 ISO-8859-1*
-- Exposed JGit's internal configuration settings in gitblit.properties/web.xml (issue 93)
- Review your `gitblit.properties` or `web.xml` for detailed explanations of these settings.
- **New:** *git.packedGitWindowSize = 8k*
- **New:** *git.packedGitLimit = 10m*
- **New:** *git.deltaBaseCacheLimit = 10m*
- **New:** *git.packedGitOpenFiles = 128*
- **New:** *git.streamFileThreshold = 50m*
- **New:** *git.packedGitMmap = false*
-- Added default access restriction. Applies to new repositories and repositories that have not been configured with Gitblit. (issue 88)
- **New:** *git.defaultAccessRestriction = NONE*
-- Added Ivy 2.2.0 dependency which enables Groovy Grapes, a mechanism to resolve and retrieve library dependencies from a Maven 2 repository within a Groovy push hook script
-- Added setting to control Groovy Grape root folder (location where resolved dependencies are stored)
- [Grape](http://groovy.codehaus.org/Grape) allows you to add Maven dependencies to your pre-/post-receive hook script classpath.
- **New:** *groovy.grapeFolder = groovy/grape*
+- Added setting to allow specification of a robots.txt file (issue 99)
+ **New:** *web.robots.txt =*
+- Added setting to control Responsive layout or Fixed-Width layout (issue 101)
+ Responsive layout is now the default. This layout gracefully scales the web ui from a desktop layout to a mobile layout by hiding page components. It is easy to try, just resize your browser or point your Android/iOS device to the url of your Gitblit install.
+ **New:** *web.useResponsiveLayout = true*
+- Added setting to control charsets for blob string decoding. Default encodings are UTF-8, ISO-8859-1, and server's default charset. (issue 97)
+ **New:** *web.blobEncodings = UTF-8 ISO-8859-1*
+- Exposed JGit's internal configuration settings in gitblit.properties/web.xml (issue 93)
+ Review your `gitblit.properties` or `web.xml` for detailed explanations of these settings.
+ **New:** *git.packedGitWindowSize = 8k*
+ **New:** *git.packedGitLimit = 10m*
+ **New:** *git.deltaBaseCacheLimit = 10m*
+ **New:** *git.packedGitOpenFiles = 128*
+ **New:** *git.streamFileThreshold = 50m*
+ **New:** *git.packedGitMmap = false*
+- Added default access restriction. Applies to new repositories and repositories that have not been configured with Gitblit. (issue 88)
+ **New:** *git.defaultAccessRestriction = NONE*
+- Added Ivy 2.2.0 dependency which enables Groovy Grapes, a mechanism to resolve and retrieve library dependencies from a Maven 2 repository within a Groovy push hook script
+- Added setting to control Groovy Grape root folder (location where resolved dependencies are stored)
+ [Grape](http://groovy.codehaus.org/Grape) allows you to add Maven dependencies to your pre-/post-receive hook script classpath.
+ **New:** *groovy.grapeFolder = groovy/grape*
- Added LDAP User Service with many new *realm.ldap* keys (Github/jcrygier)
-- Added support for custom repository properties for Groovy hooks (Github/jcrygier)
+- Added support for custom repository properties for Groovy hooks (Github/jcrygier)
Custom repository properties complement hook scripts by providing text field prompts in the web ui and the Gitblit Manager for the defined properties. This allows your push hooks to be parameterized.
- Added script to facilitate proxy environment setup on Linux (Github/mragab)
- Added Polish translation (Lukasz Jader)
@@ -271,32 +278,32 @@ Make sure to properly set *web.blobEncodings* before starting Gitblit if you are #### additions
-- Added optional Lucene branch indexing (issue 16)
- **New:** *web.allowLuceneIndexing = true*
- **New:** *web.luceneIgnoreExtensions = 7z arc arj bin bmp dll doc docx exe gif gz jar jpg lib lzh odg odf odt pdf ppt png so swf xcf xls xlsx zip*
-Repository branches may be optionally indexed by Lucene for improved searching. To use this feature you must specify which branches to index within the *Edit Repository* page; _no repositories are automatically indexed_. Gitblit will build or incrementally update enrolled repositories on a 2 minute cycle. (i.e you will have to wait 2-3 minutes after respecifying indexed branches or pushing new commits before Gitblit will build/update the repository's Lucene index.)
-If a repository has Lucene-indexed branches the *search* form on the repository pages will redirect to the root-level Lucene search page and only the content of those branches can be searched.
-If the repository does not specify any indexed branches then repository commit-traversal search is used.
-**Note:** Initial indexing of an existing repository can be memory-exhaustive. Be sure to provide your Gitblit server adequate heap space to index your repositories (e.g. -Xmx1024M).
+- Added optional Lucene branch indexing (issue 16)
+ **New:** *web.allowLuceneIndexing = true*
+ **New:** *web.luceneIgnoreExtensions = 7z arc arj bin bmp dll doc docx exe gif gz jar jpg lib lzh odg odf odt pdf ppt png so swf xcf xls xlsx zip*
+Repository branches may be optionally indexed by Lucene for improved searching. To use this feature you must specify which branches to index within the *Edit Repository* page; _no repositories are automatically indexed_. Gitblit will build or incrementally update enrolled repositories on a 2 minute cycle. (i.e you will have to wait 2-3 minutes after respecifying indexed branches or pushing new commits before Gitblit will build/update the repository's Lucene index.)
+If a repository has Lucene-indexed branches the *search* form on the repository pages will redirect to the root-level Lucene search page and only the content of those branches can be searched.
+If the repository does not specify any indexed branches then repository commit-traversal search is used.
+**Note:** Initial indexing of an existing repository can be memory-exhaustive. Be sure to provide your Gitblit server adequate heap space to index your repositories (e.g. -Xmx1024M).
See the [setup](setup.html) page for additional details.
-- Allow specifying timezone to use for Gitblit which is independent of both the JVM and the system timezone (issue 54)
- **New:** *web.timezone =*
-- Added a built-in AJP connector for integrating Gitblit GO into an Apache mod_proxy setup (issue 59)
- **New:** *server.ajpPort = 0*
+- Allow specifying timezone to use for Gitblit which is independent of both the JVM and the system timezone (issue 54)
+ **New:** *web.timezone =*
+- Added a built-in AJP connector for integrating Gitblit GO into an Apache mod_proxy setup (issue 59)
+ **New:** *server.ajpPort = 0*
**New:** *server.ajpBindInterface = localhost*
-- On the Repositories page show a bang *!* character in the color swatch of a repository with a working copy (issue 49)
+- On the Repositories page show a bang *!* character in the color swatch of a repository with a working copy (issue 49)
Push requests to these repositories will be rejected.
- On all non-bare Repository pages show *WORKING COPY* in the upper right corner (issue 49)
-- New setting to prevent display/serving non-bare repositories
+- New setting to prevent display/serving non-bare repositories
**New:** *git.onlyAccessBareRepositories = false*
-- Added *protect-refs.groovy* (Github/plm)
+- Added *protect-refs.groovy* (Github/plm)
- Allow setting default branch (relinking HEAD) to a branch or a tag (Github/plm)
- Added Ubuntu service init script (issue 72)
- Added partial Japanese translation (Github/zakki)
-#### fixes
+#### fixes
-- Ensure that Welcome message is parsed using UTF-8 encoding (issue 74)
+- Ensure that Welcome message is parsed using UTF-8 encoding (issue 74)
- Activity page chart layout broken by Google (issue 73)
- Uppercase repositories not selectable in edit palettes (issue 71)
- Not all git notes were properly displayed on the commit page (issue 70)
@@ -305,7 +312,7 @@ Push requests to these repositories will be rejected. - Fixed possible nullpointer from the servlet container on startup (issue 67)
- Fixed UTF-8 encoding bug on diff page (issue 66)
- Fixed timezone bugs on the activity page (issue 54)
-- Prevent add/edit team with no selected repositories (issue 56)
+- Prevent add/edit team with no selected repositories (issue 56)
- Disallow browser autocomplete on add/edit user/team/repository pages
- Fixed username case-sensitivity issues (issue 43)
- Disregard searching a subfolder if Gitblit does not have filesystem permissions (Github/lemval issue 51)
@@ -341,31 +348,31 @@ Push requests to these repositories will be rejected. #### additions
-- Platform-independent, Groovy push hook script mechanism.
-Hook scripts can be set per-repository, per-team, or globally for all repositories.
- **New:** *groovy.scriptsFolder = groovy*
- **New:** *groovy.preReceiveScripts =*
+- Platform-independent, Groovy push hook script mechanism.
+Hook scripts can be set per-repository, per-team, or globally for all repositories.
+ **New:** *groovy.scriptsFolder = groovy*
+ **New:** *groovy.preReceiveScripts =*
**New:** *groovy.postReceiveScripts =*
-- *sendmail.groovy* for optional email notifications on push.
+- *sendmail.groovy* for optional email notifications on push.
You must properly configure your SMTP server settings in `gitblit.properties` or `web.xml` to use *sendmail.groovy*.
-- New global key for mailing lists. This is used in conjunction with the *sendmail.groovy* hook script. All repositories that use the *sendmail.groovy* script will include these addresses in the notification process. Please see the Setup page for more details about configuring sendmail.
+- New global key for mailing lists. This is used in conjunction with the *sendmail.groovy* hook script. All repositories that use the *sendmail.groovy* script will include these addresses in the notification process. Please see the Setup page for more details about configuring sendmail.
**New:** *mail.mailingLists =*
- *com.gitblit.GitblitUserService*. This is a wrapper object for the built-in user service implementations. For those wanting to only implement custom authentication it is recommended to subclass GitblitUserService and override the appropriate methods. Going forward, this will help insulate custom authentication from new IUserService API and/or changes in model classes.
-- New default user service implementation: *com.gitblit.ConfigUserService* (`users.conf`)
-This user service implementation allows for serialization and deserialization of more sophisticated Gitblit User objects without requiring the encoding trickery now present in FileUserService (users.properties). This will open the door for more advanced Gitblit features.
-For those upgrading from an earlier Gitblit version, a `users.conf` file will automatically be created for you from your existing `users.properties` file on your first launch of Gitblit <u>however</u> you will have to manually set *realm.userService=users.conf* to switch to the new user service.
-The original `users.properties` file and it's corresponding implementation are **deprecated**.
+- New default user service implementation: *com.gitblit.ConfigUserService* (`users.conf`)
+This user service implementation allows for serialization and deserialization of more sophisticated Gitblit User objects without requiring the encoding trickery now present in FileUserService (users.properties). This will open the door for more advanced Gitblit features.
+For those upgrading from an earlier Gitblit version, a `users.conf` file will automatically be created for you from your existing `users.properties` file on your first launch of Gitblit <u>however</u> you will have to manually set *realm.userService=users.conf* to switch to the new user service.
+The original `users.properties` file and it's corresponding implementation are **deprecated**.
**New:** *realm.userService = users.conf*
- Teams for specifying user-repository access in bulk. Teams may also specify mailing lists addresses and pre- & post- receive hook scripts.
-- Gravatar integration
- **New:** *web.allowGravatar = true*
-- Activity page for aggregated repository activity. This is a timeline of commit activity over the last N days for one or more repositories.
- **New:** *web.activityDuration = 14*
- **New:** *web.timeFormat = HH:mm*
- **New:** *web.datestampLongFormat = EEEE, MMMM d, yyyy*
-- *Filters* menu for the Repositories page and Activity page. You can filter by federation set, team, and simple custom regular expressions. Custom expressions can be stored in `gitblit.properties` or `web.xml` or directly defined in your url (issue 27)
+- Gravatar integration
+ **New:** *web.allowGravatar = true*
+- Activity page for aggregated repository activity. This is a timeline of commit activity over the last N days for one or more repositories.
+ **New:** *web.activityDuration = 14*
+ **New:** *web.timeFormat = HH:mm*
+ **New:** *web.datestampLongFormat = EEEE, MMMM d, yyyy*
+- *Filters* menu for the Repositories page and Activity page. You can filter by federation set, team, and simple custom regular expressions. Custom expressions can be stored in `gitblit.properties` or `web.xml` or directly defined in your url (issue 27)
**New:** *web.customFilters=*
-- Flash-based 1-step *copy to clipboard* of the primary repository url based on Clippy
+- Flash-based 1-step *copy to clipboard* of the primary repository url based on Clippy
**New:** *web.allowFlashCopyToClipboard = true*
- JavaScript-based 3-step (click, ctrl+c, enter) *copy to clipboard* of the primary repository url in the event that you do not want to use Flash on your installation
- Empty repositories now link to an *empty repository* page which gives some direction to the user for the next step in using Gitblit. This page displays the primary push/clone url of the repository and gives sample syntax for the git command-line client. (issue 31)
@@ -375,7 +382,7 @@ The original `users.properties` file and it's corresponding implementation are * #### changes
- Dropped display of trailing .git from repository names
-- Gitblit GO is now monolithic like the WAR build. (issue 30)
+- Gitblit GO is now monolithic like the WAR build. (issue 30)
This change helps adoption of GO in environments without an internet connection or with a restricted connection.
- Unit testing framework has been migrated to JUnit4 syntax and the test suite has been redesigned to run all unit tests, including rpc, federation, and git push/clone tests
@@ -387,7 +394,7 @@ This change helps adoption of GO in environments without an internet connection #### dependency changes
- updated to JGit 1.2.0
-- added Groovy 1.8.5
+- added Groovy 1.8.5
- added Clippy (bundled)
<hr/>
@@ -395,25 +402,25 @@ This change helps adoption of GO in environments without an internet connection **0.7.0** *released 2011-11-11*
- **security**: fixed security hole when cloning clone-restricted repository with TortoiseGit (issue 28)
-- improved: updated ui with Twitter's Bootstrap CSS toolkit
+- improved: updated ui with Twitter's Bootstrap CSS toolkit
**New:** *web.loginMessage = gitblit*
- improved: repositories list performance by caching repository sizes (issue 27)
- improved: summary page performance by caching metric calculations (issue 25)
-- added: authenticated JSON RPC mechanism
- **New:** *web.enableRpcServlet = true*
- **New:** *web.enableRpcManagement = false*
+- added: authenticated JSON RPC mechanism
+ **New:** *web.enableRpcServlet = true*
+ **New:** *web.enableRpcManagement = false*
**New:** *web.enableRpcAdministration = false*
- added: Gitblit API RSS/JSON RPC library
- added: Gitblit Manager (Java/Swing Application) for remote administration of a Gitblit server.
- added: per-repository setting to skip size calculation (faster repositories page loading)
- added: per-repository setting to skip summary metrics calculation (faster summary page loading)
- added: IUserService.setup(IStoredSettings) for custom user service implementations
-- added: setting to control Gitblit GO context path for proxy setups *(Github/trygvis)*
+- added: setting to control Gitblit GO context path for proxy setups *(Github/trygvis)*
**New:** *server.contextPath = /*
- added: *combined-md5* password storage option which stores the hash of username+password as the password *(Github/alyandon)*
- added: repository owners are automatically granted access for git, feeds, and zip downloads without explicitly selecting them *(Github/dadalar)*
- added: RSS feeds now include regex substitutions on commit messages for bug trackers, etc
-- fixed: federation protocol timestamps. dates are now serialized to the [iso8601](http://en.wikipedia.org/wiki/ISO_8601) standard.
+- fixed: federation protocol timestamps. dates are now serialized to the [iso8601](http://en.wikipedia.org/wiki/ISO_8601) standard.
**This breaks 0.6.0 federation clients/servers.**
- fixed: collision on rename for repositories and users
- fixed: Gitblit can now browse the Linux kernel repository (issue 25)
@@ -430,15 +437,15 @@ This change helps adoption of GO in environments without an internet connection **0.6.0** *released 2011-09-27*
-- added: federation feature to allow gitblit instances (or gitblit federation clients) to pull repositories and, optionally, settings and accounts from other gitblit instances. This is something like [svn-sync](http://svnbook.red-bean.com/en/1.5/svn.ref.svnsync.html) for gitblit.
- **New:** *federation.name =*
- **New:** *federation.passphrase =*
- **New:** *federation.allowProposals = false*
- **New:** *federation.proposalsFolder = proposals*
- **New:** *federation.defaultFrequency = 60 mins*
- **New:** *federation.sets =*
- **New:** *mail.* settings for sending emails
- **New:** user role *#notfederated* to prevent a user account from being pulled by a federated Gitblit instance
+- added: federation feature to allow gitblit instances (or gitblit federation clients) to pull repositories and, optionally, settings and accounts from other gitblit instances. This is something like [svn-sync](http://svnbook.red-bean.com/en/1.5/svn.ref.svnsync.html) for gitblit.
+ **New:** *federation.name =*
+ **New:** *federation.passphrase =*
+ **New:** *federation.allowProposals = false*
+ **New:** *federation.proposalsFolder = proposals*
+ **New:** *federation.defaultFrequency = 60 mins*
+ **New:** *federation.sets =*
+ **New:** *mail.* settings for sending emails
+ **New:** user role *#notfederated* to prevent a user account from being pulled by a federated Gitblit instance
- added: google-gson dependency
- added: javamail dependency
- updated: MarkdownPapers 1.1.1
@@ -458,9 +465,9 @@ This change helps adoption of GO in environments without an internet connection - fixed: users can now change their passwords (issue 1)
- fixed: always show root repository group first, i.e. don't sort root group with other groups
- fixed: tone-down repository group header color
-- added: optionally display repository on-disk size on repositories page
+- added: optionally display repository on-disk size on repositories page
**New:** *web.showRepositorySizes = true*
-- added: forward-slashes ('/', %2F) can be encoded using a custom character to workaround some servlet container default security measures for proxy servers
+- added: forward-slashes ('/', %2F) can be encoded using a custom character to workaround some servlet container default security measures for proxy servers
**New:** *web.forwardSlashCharacter = /*
- updated: MarkdownPapers 1.1.0
- updated: Jetty 7.4.3
diff --git a/gitblit.iml b/gitblit.iml index 12f69f38..7f21c49a 100644 --- a/gitblit.iml +++ b/gitblit.iml @@ -77,24 +77,24 @@ </library> </orderEntry> <orderEntry type="module-library"> - <library name="jetty-webapp-7.6.7.v20120910.jar"> + <library name="jetty-webapp-7.6.8.v20121106.jar"> <CLASSES> - <root url="jar://$MODULE_DIR$/ext/jetty-webapp-7.6.7.v20120910.jar!/" /> + <root url="jar://$MODULE_DIR$/ext/jetty-webapp-7.6.8.v20121106.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES> - <root url="jar://$MODULE_DIR$/ext/src/jetty-webapp-7.6.7.v20120910-sources.jar!/" /> + <root url="jar://$MODULE_DIR$/ext/src/jetty-webapp-7.6.8.v20121106-sources.jar!/" /> </SOURCES> </library> </orderEntry> <orderEntry type="module-library"> - <library name="jetty-ajp-7.6.7.v20120910.jar"> + <library name="jetty-ajp-7.6.8.v20121106.jar"> <CLASSES> - <root url="jar://$MODULE_DIR$/ext/jetty-ajp-7.6.7.v20120910.jar!/" /> + <root url="jar://$MODULE_DIR$/ext/jetty-ajp-7.6.8.v20121106.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES> - <root url="jar://$MODULE_DIR$/ext/src/jetty-ajp-7.6.7.v20120910-sources.jar!/" /> + <root url="jar://$MODULE_DIR$/ext/src/jetty-ajp-7.6.8.v20121106-sources.jar!/" /> </SOURCES> </library> </orderEntry> @@ -196,13 +196,13 @@ </library> </orderEntry> <orderEntry type="module-library"> - <library name="markdownpapers-core-1.2.7.jar"> + <library name="markdownpapers-core-1.3.2.jar"> <CLASSES> - <root url="jar://$MODULE_DIR$/ext/markdownpapers-core-1.2.7.jar!/" /> + <root url="jar://$MODULE_DIR$/ext/markdownpapers-core-1.3.2.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES> - <root url="jar://$MODULE_DIR$/ext/src/markdownpapers-core-1.2.7-sources.jar!/" /> + <root url="jar://$MODULE_DIR$/ext/src/markdownpapers-core-1.3.2-sources.jar!/" /> </SOURCES> </library> </orderEntry> @@ -347,6 +347,28 @@ <SOURCES /> </library> </orderEntry> + <orderEntry type="module-library"> + <library name="commons-compress-1.4.1.jar"> + <CLASSES> + <root url="jar://$MODULE_DIR$/ext/commons-compress-1.4.1.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$MODULE_DIR$/ext/src/commons-compress-1.4.1-sources.jar!/" /> + </SOURCES> + </library> + </orderEntry> + <orderEntry type="module-library"> + <library name="xz-1.0.jar"> + <CLASSES> + <root url="jar://$MODULE_DIR$/ext/xz-1.0.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$MODULE_DIR$/ext/src/xz-1.0-sources.jar!/" /> + </SOURCES> + </library> + </orderEntry> <orderEntry type="module-library" scope="TEST"> <library name="junit-4.10.jar"> <CLASSES> diff --git a/groovy/sendmail-html.groovy b/groovy/sendmail-html.groovy index e0cdecdb..16920735 100644 --- a/groovy/sendmail-html.groovy +++ b/groovy/sendmail-html.groovy @@ -370,14 +370,15 @@ class HtmlMailWriter { formatter.setDiffComparator(RawTextComparator.DEFAULT);
def diffs
- RevWalk rw = new RevWalk(repository);
+ RevWalk rw = new RevWalk(repository)
if (commit.parentCount > 0) {
- RevCommit parent = commit.parents[0]
+ RevCommit parent = rw.parseCommit(commit.parents[0].id)
diffs = formatter.scan(parent.tree, commit.tree)
} else {
diffs = formatter.scan(new EmptyTreeIterator(),
new CanonicalTreeParser(null, rw.objectReader, commit.tree))
}
+ rw.dispose()
// Write status table
builder.table('class':"plain") {
tbody() {
diff --git a/src/com/gitblit/AuthenticationFilter.java b/src/com/gitblit/AuthenticationFilter.java index 64aa4411..eb6e95b7 100644 --- a/src/com/gitblit/AuthenticationFilter.java +++ b/src/com/gitblit/AuthenticationFilter.java @@ -16,9 +16,7 @@ package com.gitblit;
import java.io.IOException;
-import java.nio.charset.Charset;
import java.security.Principal;
-import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@@ -37,7 +35,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import com.gitblit.models.UserModel;
-import com.gitblit.utils.Base64;
import com.gitblit.utils.StringUtils;
/**
@@ -51,9 +48,7 @@ import com.gitblit.utils.StringUtils; */
public abstract class AuthenticationFilter implements Filter {
- protected static final String BASIC = "Basic";
-
- protected static final String CHALLENGE = BASIC + " realm=\"" + Constants.NAME + "\"";
+ protected static final String CHALLENGE = "Basic realm=\"" + Constants.NAME + "\"";
protected static final String SESSION_SECURED = "com.gitblit.secured";
@@ -103,40 +98,8 @@ public abstract class AuthenticationFilter implements Filter { * @return user
*/
protected UserModel getUser(HttpServletRequest httpRequest) {
- UserModel user = null;
- // try request authentication
- user = GitBlit.self().authenticate(httpRequest);
- if (user != null) {
- return user;
- } else if (requiresClientCertificate()) {
- // http request does not have a valid certificate
- // and the filter requires one
- return null;
- }
-
- // look for client authorization credentials in header
- final String authorization = httpRequest.getHeader("Authorization");
- if (authorization != null && authorization.startsWith(BASIC)) {
- // Authorization: Basic base64credentials
- String base64Credentials = authorization.substring(BASIC.length()).trim();
- String credentials = new String(Base64.decode(base64Credentials),
- Charset.forName("UTF-8"));
- // credentials = username:password
- final String[] values = credentials.split(":",2);
-
- if (values.length == 2) {
- String username = values[0];
- char[] password = values[1].toCharArray();
- user = GitBlit.self().authenticate(username, password);
- if (user != null) {
- return user;
- }
- }
- if (GitBlit.isDebugMode()) {
- logger.info(MessageFormat.format("AUTH: invalid credentials ({0})", credentials));
- }
- }
- return null;
+ UserModel user = GitBlit.self().authenticate(httpRequest, requiresClientCertificate());
+ return user;
}
/**
diff --git a/src/com/gitblit/Constants.java b/src/com/gitblit/Constants.java index 4669c4c9..d152651b 100644 --- a/src/com/gitblit/Constants.java +++ b/src/com/gitblit/Constants.java @@ -399,7 +399,7 @@ public class Constants { }
public static enum AuthenticationType {
- CREDENTIALS, COOKIE, CERTIFICATE;
+ CREDENTIALS, COOKIE, CERTIFICATE, CONTAINER;
public boolean isStandard() {
return ordinal() <= COOKIE.ordinal();
diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index 69135c49..c2d4a85a 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -24,6 +24,8 @@ import java.io.InputStreamReader; import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.security.Principal;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -98,6 +100,7 @@ import com.gitblit.models.SettingModel; import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.Base64;
import com.gitblit.utils.ByteFormat;
import com.gitblit.utils.ContainerUtils;
import com.gitblit.utils.DeepCopier;
@@ -567,6 +570,20 @@ public class GitBlit implements ServletContextListener { * @return a user object or null
*/
public UserModel authenticate(HttpServletRequest httpRequest) {
+ return authenticate(httpRequest, false);
+ }
+
+ /**
+ * Authenticate a user based on HTTP request parameters.
+ *
+ * Authentication by X509Certificate, servlet container principal, cookie,
+ * and BASIC header.
+ *
+ * @param httpRequest
+ * @param requiresCertificate
+ * @return a user object or null
+ */
+ public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
// try to authenticate by certificate
boolean checkValidity = settings.getBoolean(Keys.git.enforceCertificateValidity, true);
String [] oids = getStrings(Keys.git.certificateUsernameOIDs).toArray(new String[0]);
@@ -574,39 +591,85 @@ public class GitBlit implements ServletContextListener { if (model != null) {
// grab real user model and preserve certificate serial number
UserModel user = getUserModel(model.username);
+ X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest);
if (user != null) {
- RequestCycle requestCycle = RequestCycle.get();
- if (requestCycle != null) {
- // flag the Wicket session, if this is a Wicket request
- GitBlitWebSession session = GitBlitWebSession.get();
- session.authenticationType = AuthenticationType.CERTIFICATE;
- }
- X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest);
+ flagWicketSession(AuthenticationType.CERTIFICATE);
logger.info(MessageFormat.format("{0} authenticated by client certificate {1} from {2}",
user.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
return user;
+ } else {
+ logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted client certificate ({1}) authentication from {2}",
+ model.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
+ }
+ }
+
+ if (requiresCertificate) {
+ // caller requires client certificate authentication (e.g. git servlet)
+ return null;
+ }
+
+ // try to authenticate by servlet container principal
+ Principal principal = httpRequest.getUserPrincipal();
+ if (principal != null) {
+ UserModel user = getUserModel(principal.getName());
+ if (user != null) {
+ flagWicketSession(AuthenticationType.CONTAINER);
+ logger.info(MessageFormat.format("{0} authenticated by servlet container principal from {1}",
+ user.username, httpRequest.getRemoteAddr()));
+ return user;
+ } else {
+ logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted servlet container authentication from {1}",
+ principal.getName(), httpRequest.getRemoteAddr()));
}
}
// try to authenticate by cookie
- Cookie[] cookies = httpRequest.getCookies();
- if (allowCookieAuthentication() && cookies != null && cookies.length > 0) {
- // Grab cookie from Browser Session
- UserModel user = authenticate(cookies);
+ if (allowCookieAuthentication()) {
+ UserModel user = authenticate(httpRequest.getCookies());
if (user != null) {
- RequestCycle requestCycle = RequestCycle.get();
- if (requestCycle != null) {
- // flag the Wicket session, if this is a Wicket request
- GitBlitWebSession session = GitBlitWebSession.get();
- session.authenticationType = AuthenticationType.COOKIE;
- }
+ flagWicketSession(AuthenticationType.COOKIE);
logger.info(MessageFormat.format("{0} authenticated by cookie from {1}",
user.username, httpRequest.getRemoteAddr()));
return user;
}
}
+
+ // try to authenticate by BASIC
+ final String authorization = httpRequest.getHeader("Authorization");
+ if (authorization != null && authorization.startsWith("Basic")) {
+ // Authorization: Basic base64credentials
+ String base64Credentials = authorization.substring("Basic".length()).trim();
+ String credentials = new String(Base64.decode(base64Credentials),
+ Charset.forName("UTF-8"));
+ // credentials = username:password
+ final String[] values = credentials.split(":",2);
+
+ if (values.length == 2) {
+ String username = values[0];
+ char[] password = values[1].toCharArray();
+ UserModel user = authenticate(username, password);
+ if (user != null) {
+ flagWicketSession(AuthenticationType.CREDENTIALS);
+ logger.info(MessageFormat.format("{0} authenticated by BASIC request header from {1}",
+ user.username, httpRequest.getRemoteAddr()));
+ return user;
+ } else {
+ logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials ({1}) from {2}",
+ username, credentials, httpRequest.getRemoteAddr()));
+ }
+ }
+ }
return null;
}
+
+ protected void flagWicketSession(AuthenticationType authenticationType) {
+ RequestCycle requestCycle = RequestCycle.get();
+ if (requestCycle != null) {
+ // flag the Wicket session, if this is a Wicket request
+ GitBlitWebSession session = GitBlitWebSession.get();
+ session.authenticationType = authenticationType;
+ }
+ }
/**
* Open a file resource using the Servlet container.
@@ -693,6 +756,9 @@ public class GitBlit implements ServletContextListener { * @return true if successful
*/
public boolean deleteUser(String username) {
+ if (StringUtils.isEmpty(username)) {
+ return false;
+ }
return userService.deleteUser(username);
}
@@ -704,6 +770,9 @@ public class GitBlit implements ServletContextListener { * @return a user object or null
*/
public UserModel getUserModel(String username) {
+ if (StringUtils.isEmpty(username)) {
+ return null;
+ }
UserModel user = userService.getUserModel(username);
return user;
}
@@ -1533,6 +1602,7 @@ public class GitBlit implements ServletContextListener { } catch (Exception e) {
model.lastGC = new Date(0);
}
+ model.maxActivityCommits = getConfig(config, "maxActivityCommits", settings.getInteger(Keys.web.maxActivityCommits, 0));
model.origin = config.getString("remote", "origin", "url");
if (model.origin != null) {
model.origin = model.origin.replace('\\', '/');
@@ -1999,10 +2069,21 @@ public class GitBlit implements ServletContextListener { repository.federationStrategy.name());
config.setBoolean(Constants.CONFIG_GITBLIT, null, "isFederated", repository.isFederated);
config.setString(Constants.CONFIG_GITBLIT, null, "gcThreshold", repository.gcThreshold);
- config.setInt(Constants.CONFIG_GITBLIT, null, "gcPeriod", repository.gcPeriod);
+ if (repository.gcPeriod == settings.getInteger(Keys.git.defaultGarbageCollectionPeriod, 7)) {
+ // use default from config
+ config.unset(Constants.CONFIG_GITBLIT, null, "gcPeriod");
+ } else {
+ config.setInt(Constants.CONFIG_GITBLIT, null, "gcPeriod", repository.gcPeriod);
+ }
if (repository.lastGC != null) {
config.setString(Constants.CONFIG_GITBLIT, null, "lastGC", new SimpleDateFormat(Constants.ISO8601).format(repository.lastGC));
}
+ if (repository.maxActivityCommits == settings.getInteger(Keys.web.maxActivityCommits, 0)) {
+ // use default from config
+ config.unset(Constants.CONFIG_GITBLIT, null, "maxActivityCommits");
+ } else {
+ config.setInt(Constants.CONFIG_GITBLIT, null, "maxActivityCommits", repository.maxActivityCommits);
+ }
updateList(config, "federationSets", repository.federationSets);
updateList(config, "preReceiveScript", repository.preReceiveScripts);
diff --git a/src/com/gitblit/GitBlitServer.java b/src/com/gitblit/GitBlitServer.java index d98f8916..4c0e89f6 100644 --- a/src/com/gitblit/GitBlitServer.java +++ b/src/com/gitblit/GitBlitServer.java @@ -44,7 +44,6 @@ import org.eclipse.jetty.server.session.HashSessionManager; import org.eclipse.jetty.server.ssl.SslConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jgit.storage.file.FileBasedConfig;
@@ -242,7 +241,7 @@ public class GitBlitServer { });
if (serverKeyStore.exists()) {
- Connector secureConnector = createSSLConnector(serverKeyStore, serverTrustStore, params.storePassword,
+ Connector secureConnector = createSSLConnector(params.alias, serverKeyStore, serverTrustStore, params.storePassword,
caRevocationList, params.useNIO, params.securePort, params.requireClientCertificates);
String bindInterface = settings.getString(Keys.server.httpsBindInterface, null);
if (!StringUtils.isEmpty(bindInterface)) {
@@ -413,6 +412,7 @@ public class GitBlitServer { * SSL renegotiation will be enabled if the JVM is 1.6.0_22 or later.
* oracle.com/technetwork/java/javase/documentation/tlsreadme2-176330.html
*
+ * @param certAlias
* @param keyStore
* @param clientTrustStore
* @param storePassword
@@ -422,52 +422,31 @@ public class GitBlitServer { * @param requireClientCertificates
* @return an https connector
*/
- private static Connector createSSLConnector(File keyStore, File clientTrustStore,
+ private static Connector createSSLConnector(String certAlias, File keyStore, File clientTrustStore,
String storePassword, File caRevocationList, boolean useNIO, int port,
boolean requireClientCertificates) {
- SslContextFactory sslContext = new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH);
+ GitblitSslContextFactory factory = new GitblitSslContextFactory(certAlias,
+ keyStore, clientTrustStore, storePassword, caRevocationList);
SslConnector connector;
if (useNIO) {
logger.info("Setting up NIO SslSelectChannelConnector on port " + port);
- SslSelectChannelConnector ssl = new SslSelectChannelConnector(sslContext);
+ SslSelectChannelConnector ssl = new SslSelectChannelConnector(factory);
ssl.setSoLingerTime(-1);
if (requireClientCertificates) {
- sslContext.setNeedClientAuth(true);
+ factory.setNeedClientAuth(true);
} else {
- sslContext.setWantClientAuth(true);
+ factory.setWantClientAuth(true);
}
ssl.setThreadPool(new QueuedThreadPool(20));
connector = ssl;
} else {
logger.info("Setting up NIO SslSocketConnector on port " + port);
- SslSocketConnector ssl = new SslSocketConnector(sslContext);
+ SslSocketConnector ssl = new SslSocketConnector(factory);
connector = ssl;
}
- // disable renegotiation unless this is a patched JVM
- boolean allowRenegotiation = false;
- String v = System.getProperty("java.version");
- if (v.startsWith("1.7")) {
- allowRenegotiation = true;
- } else if (v.startsWith("1.6")) {
- // 1.6.0_22 was first release with RFC-5746 implemented fix.
- if (v.indexOf('_') > -1) {
- String b = v.substring(v.indexOf('_') + 1);
- if (Integer.parseInt(b) >= 22) {
- allowRenegotiation = true;
- }
- }
- }
- if (allowRenegotiation) {
- logger.info(" allowing SSL renegotiation on Java " + v);
- sslContext.setAllowRenegotiate(allowRenegotiation);
- }
- sslContext.setKeyStorePath(keyStore.getAbsolutePath());
- sslContext.setKeyStorePassword(storePassword);
- sslContext.setTrustStore(clientTrustStore.getAbsolutePath());
- sslContext.setTrustStorePassword(storePassword);
- sslContext.setCrlPath(caRevocationList.getAbsolutePath());
connector.setPort(port);
connector.setMaxIdleTime(30000);
+
return connector;
}
@@ -596,6 +575,9 @@ public class GitBlitServer { @Parameter(names = "--ajpPort", description = "AJP port to serve. (port <= 0 will disable this connector)")
public Integer ajpPort = FILESETTINGS.getInteger(Keys.server.ajpPort, 0);
+ @Parameter(names = "--alias", description = "Alias of SSL certificate in keystore for serving https.")
+ public String alias = FILESETTINGS.getString(Keys.server.certificateAlias, "");
+
@Parameter(names = "--storePassword", description = "Password for SSL (https) keystore.")
public String storePassword = FILESETTINGS.getString(Keys.server.storePassword, "");
diff --git a/src/com/gitblit/GitblitSslContextFactory.java b/src/com/gitblit/GitblitSslContextFactory.java new file mode 100644 index 00000000..f025c452 --- /dev/null +++ b/src/com/gitblit/GitblitSslContextFactory.java @@ -0,0 +1,94 @@ +/*
+ * Copyright 2012 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.cert.CRL;
+import java.util.Collection;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Special SSL context factory that configures Gitblit GO and replaces the
+ * primary trustmanager with a GitblitTrustManager.
+ *
+ * @author James Moger
+ */
+public class GitblitSslContextFactory extends SslContextFactory {
+
+ private static final Logger logger = LoggerFactory.getLogger(GitblitSslContextFactory.class);
+
+ private final File caRevocationList;
+
+ public GitblitSslContextFactory(String certAlias, File keyStore, File clientTrustStore,
+ String storePassword, File caRevocationList) {
+ super(keyStore.getAbsolutePath());
+
+ this.caRevocationList = caRevocationList;
+
+ // disable renegotiation unless this is a patched JVM
+ boolean allowRenegotiation = false;
+ String v = System.getProperty("java.version");
+ if (v.startsWith("1.7")) {
+ allowRenegotiation = true;
+ } else if (v.startsWith("1.6")) {
+ // 1.6.0_22 was first release with RFC-5746 implemented fix.
+ if (v.indexOf('_') > -1) {
+ String b = v.substring(v.indexOf('_') + 1);
+ if (Integer.parseInt(b) >= 22) {
+ allowRenegotiation = true;
+ }
+ }
+ }
+ if (allowRenegotiation) {
+ logger.info(" allowing SSL renegotiation on Java " + v);
+ setAllowRenegotiate(allowRenegotiation);
+ }
+
+
+ if (!StringUtils.isEmpty(certAlias)) {
+ logger.info(" certificate alias = " + certAlias);
+ setCertAlias(certAlias);
+ }
+ setKeyStorePassword(storePassword);
+ setTrustStore(clientTrustStore.getAbsolutePath());
+ setTrustStorePassword(storePassword);
+
+ logger.info(" keyStorePath = " + keyStore.getAbsolutePath());
+ logger.info(" trustStorePath = " + clientTrustStore.getAbsolutePath());
+ logger.info(" crlPath = " + caRevocationList.getAbsolutePath());
+ }
+
+ @Override
+ protected TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls)
+ throws Exception {
+ TrustManager[] managers = super.getTrustManagers(trustStore, crls);
+ X509TrustManager delegate = (X509TrustManager) managers[0];
+ GitblitTrustManager root = new GitblitTrustManager(delegate, caRevocationList);
+
+ // replace first manager with the GitblitTrustManager
+ managers[0] = root;
+ return managers;
+ }
+}
diff --git a/src/com/gitblit/GitblitTrustManager.java b/src/com/gitblit/GitblitTrustManager.java new file mode 100644 index 00000000..4127caf4 --- /dev/null +++ b/src/com/gitblit/GitblitTrustManager.java @@ -0,0 +1,125 @@ +/*
+ * Copyright 2012 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.text.MessageFormat;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.net.ssl.X509TrustManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * GitblitTrustManager is a wrapper trust manager that hot-reloads a local file
+ * CRL and enforces client certificate revocations. The GitblitTrustManager
+ * also implements fuzzy revocation enforcement in case of issuer mismatch BUT
+ * serial number match. These rejecions are specially noted in the log.
+ *
+ * @author James Moger
+ */
+public class GitblitTrustManager implements X509TrustManager {
+
+ private static final Logger logger = LoggerFactory.getLogger(GitblitTrustManager.class);
+
+ private final X509TrustManager delegate;
+ private final File caRevocationList;
+
+ private final AtomicLong lastModified = new AtomicLong(0);
+ private volatile X509CRL crl;
+
+ public GitblitTrustManager(X509TrustManager delegate, File crlFile) {
+ this.delegate = delegate;
+ this.caRevocationList = crlFile;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ X509Certificate cert = chain[0];
+ if (isRevoked(cert)) {
+ String message = MessageFormat.format("Rejecting revoked certificate {0,number,0} for {1}",
+ cert.getSerialNumber(), cert.getSubjectDN().getName());
+ logger.warn(message);
+ throw new CertificateException(message);
+ }
+ delegate.checkClientTrusted(chain, authType);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ delegate.checkServerTrusted(chain, authType);
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return delegate.getAcceptedIssuers();
+ }
+
+ protected boolean isRevoked(X509Certificate cert) {
+ if (!caRevocationList.exists()) {
+ return false;
+ }
+ read();
+
+ if (crl.isRevoked(cert)) {
+ // exact cert is revoked
+ return true;
+ }
+
+ X509CRLEntry entry = crl.getRevokedCertificate(cert.getSerialNumber());
+ if (entry != null) {
+ logger.warn("Certificate issuer does not match CRL issuer, but serial number has been revoked!");
+ logger.warn(" cert issuer = " + cert.getIssuerX500Principal());
+ logger.warn(" crl issuer = " + crl.getIssuerX500Principal());
+ return true;
+ }
+
+ return false;
+ }
+
+ protected synchronized void read() {
+ if (lastModified.get() == caRevocationList.lastModified()) {
+ return;
+ }
+ logger.info("Reloading CRL from " + caRevocationList.getAbsolutePath());
+ InputStream inStream = null;
+ try {
+ inStream = new FileInputStream(caRevocationList);
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ X509CRL list = (X509CRL)cf.generateCRL(inStream);
+ crl = list;
+ lastModified.set(caRevocationList.lastModified());
+ } catch (Exception e) {
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file diff --git a/src/com/gitblit/authority/GitblitAuthority.java b/src/com/gitblit/authority/GitblitAuthority.java index d97a8e39..909831fe 100644 --- a/src/com/gitblit/authority/GitblitAuthority.java +++ b/src/com/gitblit/authority/GitblitAuthority.java @@ -21,6 +21,7 @@ import java.awt.Desktop; import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
+import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
@@ -69,6 +70,7 @@ import javax.swing.JSplitPane; import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
+import javax.swing.JToolBar;
import javax.swing.RowFilter;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
@@ -565,15 +567,26 @@ public class GitblitAuthority extends JFrame implements X509Log { }
};
- JTextField durationTF = new JTextField(4);
- durationTF.setInputVerifier(verifier);
- durationTF.setVerifyInputWhenFocusTarget(true);
- durationTF.setText("" + certificateConfig.duration);
- JPanel durationPanel = Utils.newFieldPanel(Translation.get("gb.duration"), durationTF, Translation.get("gb.duration.days").replace("{0}", "").trim());
+ JTextField siteNameTF = new JTextField(20);
+ siteNameTF.setText(gitblitSettings.getString(Keys.web.siteName, "Gitblit"));
+ JPanel siteNamePanel = Utils.newFieldPanel(Translation.get("gb.siteName"),
+ siteNameTF, Translation.get("gb.siteNameDescription"));
+
+ JTextField validityTF = new JTextField(4);
+ validityTF.setInputVerifier(verifier);
+ validityTF.setVerifyInputWhenFocusTarget(true);
+ validityTF.setText("" + certificateConfig.duration);
+ JPanel validityPanel = Utils.newFieldPanel(Translation.get("gb.validity"),
+ validityTF, Translation.get("gb.duration.days").replace("{0}", "").trim());
+
+ JPanel p1 = new JPanel(new GridLayout(0, 1, 5, 2));
+ p1.add(siteNamePanel);
+ p1.add(validityPanel);
+
DefaultOidsPanel oids = new DefaultOidsPanel(metadata);
JPanel panel = new JPanel(new BorderLayout());
- panel.add(durationPanel, BorderLayout.NORTH);
+ panel.add(p1, BorderLayout.NORTH);
panel.add(oids, BorderLayout.CENTER);
int result = JOptionPane.showConfirmDialog(GitblitAuthority.this,
@@ -582,9 +595,13 @@ public class GitblitAuthority extends JFrame implements X509Log { if (result == JOptionPane.OK_OPTION) {
try {
oids.update(metadata);
- certificateConfig.duration = Integer.parseInt(durationTF.getText());
+ certificateConfig.duration = Integer.parseInt(validityTF.getText());
certificateConfig.store(config, metadata);
config.save();
+
+ Map<String, String> updates = new HashMap<String, String>();
+ updates.put(Keys.web.siteName, siteNameTF.getText());
+ gitblitSettings.saveSettings(updates);
} catch (Exception e1) {
Utils.showException(GitblitAuthority.this, e1);
}
@@ -607,7 +624,8 @@ public class GitblitAuthority extends JFrame implements X509Log { }
final Date expires = dialog.getExpiration();
final String hostname = dialog.getHostname();
-
+ final boolean serveCertificate = dialog.isServeCertificate();
+
AuthorityWorker worker = new AuthorityWorker(GitblitAuthority.this) {
@Override
@@ -623,17 +641,31 @@ public class GitblitAuthority extends JFrame implements X509Log { // generate new SSL certificate
X509Metadata metadata = new X509Metadata(hostname, caKeystorePassword);
+ setMetadataDefaults(metadata);
metadata.notAfter = expires;
File serverKeystoreFile = new File(folder, X509Utils.SERVER_KEY_STORE);
X509Certificate cert = X509Utils.newSSLCertificate(metadata, caPrivateKey, caCert, serverKeystoreFile, GitblitAuthority.this);
- return cert != null;
+ boolean hasCert = cert != null;
+ if (hasCert && serveCertificate) {
+ // update Gitblit https connector alias
+ Map<String, String> updates = new HashMap<String, String>();
+ updates.put(Keys.server.certificateAlias, metadata.commonName);
+ gitblitSettings.saveSettings(updates);
+ }
+ return hasCert;
}
@Override
protected void onSuccess() {
- JOptionPane.showMessageDialog(GitblitAuthority.this,
+ if (serveCertificate) {
+ JOptionPane.showMessageDialog(GitblitAuthority.this,
+ MessageFormat.format(Translation.get("gb.sslCertificateGeneratedRestart"), hostname),
+ Translation.get("gb.newSSLCertificate"), JOptionPane.INFORMATION_MESSAGE);
+ } else {
+ JOptionPane.showMessageDialog(GitblitAuthority.this,
MessageFormat.format(Translation.get("gb.sslCertificateGenerated"), hostname),
Translation.get("gb.newSSLCertificate"), JOptionPane.INFORMATION_MESSAGE);
+ }
}
};
@@ -713,7 +745,8 @@ public class GitblitAuthority extends JFrame implements X509Log { }
});
- JPanel buttonControls = new JPanel(new FlowLayout(FlowLayout.LEFT, Utils.MARGIN, Utils.MARGIN));
+ JToolBar buttonControls = new JToolBar(JToolBar.HORIZONTAL);
+ buttonControls.setFloatable(false);
buttonControls.add(certificateDefaultsButton);
buttonControls.add(newSSLCertificate);
buttonControls.add(emailBundle);
diff --git a/src/com/gitblit/authority/NewSSLCertificateDialog.java b/src/com/gitblit/authority/NewSSLCertificateDialog.java index 1ff542a2..821e9e9f 100644 --- a/src/com/gitblit/authority/NewSSLCertificateDialog.java +++ b/src/com/gitblit/authority/NewSSLCertificateDialog.java @@ -24,6 +24,7 @@ import java.awt.event.ActionListener; import java.util.Date;
import javax.swing.JButton;
+import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
@@ -41,6 +42,7 @@ public class NewSSLCertificateDialog extends JDialog { JDateChooser expirationDate;
JTextField hostname;
+ JCheckBox serveCertificate;
boolean isCanceled = true;
public NewSSLCertificateDialog(Frame owner, Date defaultExpiration) {
@@ -60,6 +62,7 @@ public class NewSSLCertificateDialog extends JDialog { expirationDate = new JDateChooser(defaultExpiration);
hostname = new JTextField(20);
+ serveCertificate = new JCheckBox(Translation.get("gb.serveCertificate"), true);
JPanel panel = new JPanel(new GridLayout(0, 2, Utils.MARGIN, Utils.MARGIN));
@@ -69,6 +72,9 @@ public class NewSSLCertificateDialog extends JDialog { panel.add(new JLabel(Translation.get("gb.expires")));
panel.add(expirationDate);
+ panel.add(new JLabel(""));
+ panel.add(serveCertificate);
+
JButton ok = new JButton(Translation.get("gb.ok"));
ok.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
@@ -123,7 +129,11 @@ public class NewSSLCertificateDialog extends JDialog { public Date getExpiration() {
return expirationDate.getDate();
}
-
+
+ public boolean isServeCertificate() {
+ return serveCertificate.isSelected();
+ }
+
public boolean isCanceled() {
return isCanceled;
}
diff --git a/src/com/gitblit/build/Build.java b/src/com/gitblit/build/Build.java index e8e6b45d..19d80e78 100644 --- a/src/com/gitblit/build/Build.java +++ b/src/com/gitblit/build/Build.java @@ -565,17 +565,17 @@ public class Build { "c7adc475ca40c288c93054e0f4fe58f3a98c0cb5");
public static final MavenObject JETTY = new MavenObject(
- "Jetty", "org/eclipse/jetty/aggregate", "jetty-webapp", "7.6.7.v20120910",
+ "Jetty", "org/eclipse/jetty/aggregate", "jetty-webapp", "7.6.8.v20121106",
1000000, 680000, 2720000,
- "d621fa6419aaa37edbcab8e16a5e6b05c9527e62",
- "b505f7b493c5aa262d371d90754bded8b392ffb0",
+ "6333969b4d509c4b681e05302ca7ebccb9c3efb5",
+ "354f2752ed6544296bc0fc92e533d68a5b03045b",
"");
public static final MavenObject JETTY_AJP = new MavenObject(
- "Jetty-AJP", "org/eclipse/jetty", "jetty-ajp", "7.6.7.v20120910",
+ "Jetty-AJP", "org/eclipse/jetty", "jetty-ajp", "7.6.8.v20121106",
32000, 22000, 97000,
- "578d502bc78ed7aa1c0b6afef4cd59477041ec37",
- "6cfed9a1354f720fcde12ec15d5e1ae9cf97000c",
+ "95bd1c89bb2afd4eeaabc6f4b0183a9f26a522d7",
+ "e1fc2539202ebb240a87a080bc44a24c93d7318b",
"");
public static final MavenObject SERVLET = new MavenObject(
@@ -647,10 +647,10 @@ public class Build { "");
public static final MavenObject MARKDOWNPAPERS = new MavenObject(
- "MarkdownPapers", "org/tautua/markdownpapers", "markdownpapers-core", "1.2.7",
- 87000, 58000, 268000,
- "84ac5636ac7ddfad9d2ee8456a0f4f69709b6ee0",
- "453cf00a289c46a0e4f6f019a28d2a2605f652c8",
+ "MarkdownPapers", "org/tautua/markdownpapers", "markdownpapers-core", "1.3.2",
+ 92000, 60000, 268000,
+ "da22db6660e90b9a677bbdfc2c511c619ea5c249",
+ "6a7228280a229144afe6c01351a8f44675d8524d",
"");
public static final MavenObject BOUNCYCASTLE = new MavenObject(
diff --git a/src/com/gitblit/client/EditRepositoryDialog.java b/src/com/gitblit/client/EditRepositoryDialog.java index a9274964..aa6ad58d 100644 --- a/src/com/gitblit/client/EditRepositoryDialog.java +++ b/src/com/gitblit/client/EditRepositoryDialog.java @@ -124,6 +124,8 @@ public class EditRepositoryDialog extends JDialog { private JComboBox gcPeriod;
private JTextField gcThreshold;
+
+ private JComboBox maxActivityCommits;
private RegistrantPermissionsPanel usersPalette;
@@ -225,6 +227,10 @@ public class EditRepositoryDialog extends JDialog { isFrozen = new JCheckBox(Translation.get("gb.isFrozenDescription"),
anRepository.isFrozen);
+ maxActivityCommits = new JComboBox(new Integer [] { 0, 25, 50, 75, 100, 150, 250, 500 });
+ maxActivityCommits.setSelectedItem(anRepository.maxActivityCommits);
+
+
mailingListsField = new JTextField(
ArrayUtils.isEmpty(anRepository.mailingLists) ? ""
: StringUtils.flattenStrings(anRepository.mailingLists,
@@ -314,6 +320,8 @@ public class EditRepositoryDialog extends JDialog { skipSizeCalculation));
fieldsPanel.add(newFieldPanel(Translation.get("gb.skipSummaryMetrics"),
skipSummaryMetrics));
+ fieldsPanel.add(newFieldPanel(Translation.get("gb.maxActivityCommits"),
+ maxActivityCommits));
fieldsPanel.add(newFieldPanel(Translation.get("gb.mailingLists"),
mailingListsField));
@@ -561,6 +569,7 @@ public class EditRepositoryDialog extends JDialog { repository.showReadme = showReadme.isSelected();
repository.skipSizeCalculation = skipSizeCalculation.isSelected();
repository.skipSummaryMetrics = skipSummaryMetrics.isSelected();
+ repository.maxActivityCommits = (Integer) maxActivityCommits.getSelectedItem();
repository.isFrozen = isFrozen.isSelected();
repository.allowForks = allowForks.isSelected();
diff --git a/src/com/gitblit/client/EditUserDialog.java b/src/com/gitblit/client/EditUserDialog.java index e954fed6..0400f5c9 100644 --- a/src/com/gitblit/client/EditUserDialog.java +++ b/src/com/gitblit/client/EditUserDialog.java @@ -90,7 +90,17 @@ public class EditUserDialog extends JDialog { private JCheckBox canCreateCheckbox;
private JCheckBox notFederatedCheckbox;
+
+ private JTextField organizationalUnitField;
+
+ private JTextField organizationField;
+ private JTextField localityField;
+
+ private JTextField stateProvinceField;
+
+ private JTextField countryCodeField;
+
private RegistrantPermissionsPanel repositoryPalette;
private JPalette<TeamModel> teamsPalette;
@@ -142,6 +152,12 @@ public class EditUserDialog extends JDialog { Translation.get("gb.excludeFromFederationDescription"),
anUser.excludeFromFederation);
+ organizationalUnitField = new JTextField(anUser.organizationalUnit == null ? "" : anUser.organizationalUnit, 25);
+ organizationField = new JTextField(anUser.organization == null ? "" : anUser.organization, 25);
+ localityField = new JTextField(anUser.locality == null ? "" : anUser.locality, 25);
+ stateProvinceField = new JTextField(anUser.stateProvince == null ? "" : anUser.stateProvince, 25);
+ countryCodeField = new JTextField(anUser.countryCode == null ? "" : anUser.countryCode, 15);
+
// credentials are optionally controlled by 3rd-party authentication
usernameField.setEnabled(settings.supportsCredentialChanges);
passwordField.setEnabled(settings.supportsCredentialChanges);
@@ -149,6 +165,12 @@ public class EditUserDialog extends JDialog { displayNameField.setEnabled(settings.supportsDisplayNameChanges);
emailAddressField.setEnabled(settings.supportsEmailAddressChanges);
+
+ organizationalUnitField.setEnabled(settings.supportsDisplayNameChanges);
+ organizationField.setEnabled(settings.supportsDisplayNameChanges);
+ localityField.setEnabled(settings.supportsDisplayNameChanges);
+ stateProvinceField.setEnabled(settings.supportsDisplayNameChanges);
+ countryCodeField.setEnabled(settings.supportsDisplayNameChanges);
JPanel fieldsPanel = new JPanel(new GridLayout(0, 1));
fieldsPanel.add(newFieldPanel(Translation.get("gb.username"), usernameField));
@@ -162,6 +184,13 @@ public class EditUserDialog extends JDialog { fieldsPanel.add(newFieldPanel(Translation.get("gb.excludeFromFederation"),
notFederatedCheckbox));
+ JPanel attributesPanel = new JPanel(new GridLayout(0, 1, 5, 2));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.organizationalUnit") + " (OU)", organizationalUnitField));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.organization") + " (O)", organizationField));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.locality") + " (L)", localityField));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.stateProvince") + " (ST)", stateProvinceField));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.countryCode") + " (C)", countryCodeField));
+
final Insets _insets = new Insets(5, 5, 5, 5);
repositoryPalette = new RegistrantPermissionsPanel(RegistrantType.REPOSITORY);
teamsPalette = new JPalette<TeamModel>();
@@ -170,6 +199,9 @@ public class EditUserDialog extends JDialog { JPanel fieldsPanelTop = new JPanel(new BorderLayout());
fieldsPanelTop.add(fieldsPanel, BorderLayout.NORTH);
+ JPanel attributesPanelTop = new JPanel(new BorderLayout());
+ attributesPanelTop.add(attributesPanel, BorderLayout.NORTH);
+
JPanel repositoriesPanel = new JPanel(new BorderLayout()) {
private static final long serialVersionUID = 1L;
@@ -192,6 +224,7 @@ public class EditUserDialog extends JDialog { JTabbedPane panel = new JTabbedPane(JTabbedPane.TOP);
panel.addTab(Translation.get("gb.general"), fieldsPanelTop);
+ panel.addTab(Translation.get("gb.attributes"), attributesPanelTop);
if (protocolVersion > 1) {
panel.addTab(Translation.get("gb.teamMemberships"), teamsPanel);
}
@@ -324,6 +357,12 @@ public class EditUserDialog extends JDialog { user.canCreate = canCreateCheckbox.isSelected();
user.excludeFromFederation = notFederatedCheckbox.isSelected();
+ user.organizationalUnit = organizationalUnitField.getText().trim();
+ user.organization = organizationField.getText().trim();
+ user.locality = localityField.getText().trim();
+ user.stateProvince = stateProvinceField.getText().trim();
+ user.countryCode = countryCodeField.getText().trim();
+
for (RegistrantAccessPermission rp : repositoryPalette.getPermissions()) {
user.setRepositoryPermission(rp.registrant, rp.permission);
}
diff --git a/src/com/gitblit/models/PathModel.java b/src/com/gitblit/models/PathModel.java index 8692359c..84571cbb 100644 --- a/src/com/gitblit/models/PathModel.java +++ b/src/com/gitblit/models/PathModel.java @@ -48,6 +48,10 @@ public class PathModel implements Serializable, Comparable<PathModel> { this.commitId = commitId;
}
+ public boolean isSymlink() {
+ return FileMode.SYMLINK.equals(mode);
+ }
+
public boolean isSubmodule() {
return FileMode.GITLINK.equals(mode);
}
diff --git a/src/com/gitblit/models/RepositoryModel.java b/src/com/gitblit/models/RepositoryModel.java index ed9e7188..5be33a2d 100644 --- a/src/com/gitblit/models/RepositoryModel.java +++ b/src/com/gitblit/models/RepositoryModel.java @@ -78,6 +78,7 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel public boolean verifyCommitter;
public String gcThreshold;
public int gcPeriod;
+ public int maxActivityCommits;
public transient boolean isCollectingGarbage;
public Date lastGC;
diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java index bd40985f..f1bc5efc 100644 --- a/src/com/gitblit/models/UserModel.java +++ b/src/com/gitblit/models/UserModel.java @@ -589,7 +589,7 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel> public boolean hasBranchPermission(String repositoryName, String branch) {
// Default UserModel doesn't implement branch-level security. Other Realms (i.e. Gerrit) may override this method.
- return hasRepositoryPermission(repositoryName);
+ return hasRepositoryPermission(repositoryName) || hasTeamRepositoryPermission(repositoryName);
}
public boolean isMyPersonalRepository(String repository) {
diff --git a/src/com/gitblit/utils/ActivityUtils.java b/src/com/gitblit/utils/ActivityUtils.java index e389e642..80aaebbb 100644 --- a/src/com/gitblit/utils/ActivityUtils.java +++ b/src/com/gitblit/utils/ActivityUtils.java @@ -106,7 +106,11 @@ public class ActivityUtils { }
List<RevCommit> commits = JGitUtils.getRevLog(repository,
branch, thresholdDate);
- for (RevCommit commit : commits) {
+ if (model.maxActivityCommits > 0 && commits.size() > model.maxActivityCommits) {
+ // trim commits to maximum count
+ commits = commits.subList(0, model.maxActivityCommits);
+ }
+ for (RevCommit commit : commits) {
Date date = JGitUtils.getCommitDate(commit);
String dateStr = df.format(date);
if (!activity.containsKey(dateStr)) {
diff --git a/src/com/gitblit/utils/CompressionUtils.java b/src/com/gitblit/utils/CompressionUtils.java index 7b0d0471..a8dcdd8f 100644 --- a/src/com/gitblit/utils/CompressionUtils.java +++ b/src/com/gitblit/utils/CompressionUtils.java @@ -15,27 +15,25 @@ */
package com.gitblit.utils;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
-import org.apache.commons.compress.utils.IOUtils;
+import org.apache.wicket.util.io.ByteArrayOutputStream;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
-import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
@@ -99,37 +97,35 @@ public class CompressionUtils { RevWalk rw = new RevWalk(repository);
TreeWalk tw = new TreeWalk(repository);
try {
+ tw.reset();
tw.addTree(commit.getTree());
- ZipOutputStream zos = new ZipOutputStream(os);
+ ZipArchiveOutputStream zos = new ZipArchiveOutputStream(os);
zos.setComment("Generated by Gitblit");
if (!StringUtils.isEmpty(basePath)) {
PathFilter f = PathFilter.create(basePath);
tw.setFilter(f);
}
tw.setRecursive(true);
+ MutableObjectId id = new MutableObjectId();
+ ObjectReader reader = tw.getObjectReader();
+ long modified = commit.getAuthorIdent().getWhen().getTime();
while (tw.next()) {
- if (tw.getFileMode(0) == FileMode.GITLINK) {
+ FileMode mode = tw.getFileMode(0);
+ if (mode == FileMode.GITLINK || mode == FileMode.TREE) {
continue;
}
- ZipEntry entry = new ZipEntry(tw.getPathString());
- entry.setSize(tw.getObjectReader().getObjectSize(tw.getObjectId(0),
- Constants.OBJ_BLOB));
- entry.setComment(commit.getName());
- zos.putNextEntry(entry);
+ tw.getObjectId(id, 0);
- ObjectId entid = tw.getObjectId(0);
- FileMode entmode = tw.getFileMode(0);
- RevBlob blob = (RevBlob) rw.lookupAny(entid, entmode.getObjectType());
- rw.parseBody(blob);
+ ZipArchiveEntry entry = new ZipArchiveEntry(tw.getPathString());
+ entry.setSize(reader.getObjectSize(id, Constants.OBJ_BLOB));
+ entry.setComment(commit.getName());
+ entry.setUnixMode(mode.getBits());
+ entry.setTime(modified);
+ zos.putArchiveEntry(entry);
- ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);
- byte[] tmp = new byte[4096];
- InputStream in = ldr.openStream();
- int n;
- while ((n = in.read(tmp)) > 0) {
- zos.write(tmp, 0, n);
- }
- in.close();
+ ObjectLoader ldr = repository.open(id);
+ ldr.copyTo(zos);
+ zos.closeArchiveEntry();
}
zos.finish();
success = true;
@@ -250,6 +246,7 @@ public class CompressionUtils { RevWalk rw = new RevWalk(repository);
TreeWalk tw = new TreeWalk(repository);
try {
+ tw.reset();
tw.addTree(commit.getTree());
TarArchiveOutputStream tos = new TarArchiveOutputStream(cos);
tos.setAddPaxHeadersForNonAsciiNames(true);
@@ -259,46 +256,33 @@ public class CompressionUtils { tw.setFilter(f);
}
tw.setRecursive(true);
+ MutableObjectId id = new MutableObjectId();
+ long modified = commit.getAuthorIdent().getWhen().getTime();
while (tw.next()) {
FileMode mode = tw.getFileMode(0);
- if (mode == FileMode.GITLINK) {
+ if (mode == FileMode.GITLINK || mode == FileMode.TREE) {
continue;
}
- ObjectId id = tw.getObjectId(0);
-
- // new entry
- TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString());
- entry.setSize(tw.getObjectReader().getObjectSize(id, Constants.OBJ_BLOB));
+ tw.getObjectId(id, 0);
- if (FileMode.SYMLINK.equals(mode)) {
- // symlink
- entry.setMode(mode.getBits());
-
- // read the symlink target
- ByteArrayOutputStream bs = new ByteArrayOutputStream();
- RevBlob blob = (RevBlob) rw.lookupAny(id, mode.getObjectType());
- rw.parseBody(blob);
- ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);
- IOUtils.copy(ldr.openStream(), bs);
- entry.setLinkName(bs.toString("UTF-8"));
+ ObjectLoader loader = repository.open(id);
+ if (FileMode.SYMLINK == mode) {
+ TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString(),TarArchiveEntry.LF_SYMLINK);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ loader.copyTo(bos);
+ entry.setLinkName(bos.toString());
+ entry.setModTime(modified);
+ tos.putArchiveEntry(entry);
+ tos.closeArchiveEntry();
} else {
- // regular file or executable file
+ TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString());
entry.setMode(mode.getBits());
- }
- entry.setModTime(commit.getAuthorIdent().getWhen());
-
- tos.putArchiveEntry(entry);
-
- if (!FileMode.SYMLINK.equals(mode)) {
- // write the blob
- RevBlob blob = (RevBlob) rw.lookupAny(id, mode.getObjectType());
- rw.parseBody(blob);
- ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);
- IOUtils.copy(ldr.openStream(), tos);
+ entry.setModTime(modified);
+ entry.setSize(loader.getSize());
+ tos.putArchiveEntry(entry);
+ loader.copyTo(tos);
+ tos.closeArchiveEntry();
}
-
- // close entry
- tos.closeArchiveEntry();
}
tos.finish();
tos.close();
diff --git a/src/com/gitblit/utils/HttpUtils.java b/src/com/gitblit/utils/HttpUtils.java index b40088c8..86f53cfe 100644 --- a/src/com/gitblit/utils/HttpUtils.java +++ b/src/com/gitblit/utils/HttpUtils.java @@ -178,4 +178,27 @@ public class HttpUtils { }
return null;
}
+
+ public static boolean isIpAddress(String address) {
+ if (StringUtils.isEmpty(address)) {
+ return false;
+ }
+ String [] fields = address.split("\\.");
+ if (fields.length == 4) {
+ // IPV4
+ for (String field : fields) {
+ try {
+ int value = Integer.parseInt(field);
+ if (value < 0 || value > 255) {
+ return false;
+ }
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ return true;
+ }
+ // TODO IPV6?
+ return false;
+ }
}
diff --git a/src/com/gitblit/utils/X509Utils.java b/src/com/gitblit/utils/X509Utils.java index cfad9ec0..237c8dad 100644 --- a/src/com/gitblit/utils/X509Utils.java +++ b/src/com/gitblit/utils/X509Utils.java @@ -46,11 +46,13 @@ import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
@@ -556,6 +558,16 @@ public class X509Utils { certBuilder.addExtension(X509Extension.basicConstraints, false, new BasicConstraints(false));
certBuilder.addExtension(X509Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caCert.getPublicKey()));
+ // support alternateSubjectNames for SSL certificates
+ List<GeneralName> altNames = new ArrayList<GeneralName>();
+ if (HttpUtils.isIpAddress(sslMetadata.commonName)) {
+ altNames.add(new GeneralName(GeneralName.iPAddress, sslMetadata.commonName));
+ }
+ if (altNames.size() > 0) {
+ GeneralNames subjectAltName = new GeneralNames(altNames.toArray(new GeneralName [altNames.size()]));
+ certBuilder.addExtension(X509Extension.subjectAlternativeName, false, subjectAltName);
+ }
+
ContentSigner caSigner = new JcaContentSignerBuilder(SIGNING_ALGORITHM)
.setProvider(BC).build(caPrivateKey);
X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC)
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index 6ee12990..5b42a2c0 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -430,4 +430,13 @@ gb.pleaseGenerateClientCertificate = Please generate a client certificate for {0 gb.clientCertificateBundleSent = Client certificate bundle for {0} sent
gb.enterKeystorePassword = Please enter the Gitblit keystore password
gb.warning = warning
-gb.jceWarning = Your Java Runtime Environment does not have the \"JCE Unlimited Strength Jurisdiction Policy\" files.\nThis will limit the length of passwords you may use to encrypt your keystores to 7 characters.\nThese policy files are an optional download from Oracle.\n\nWould you like to continue and generate the certificate infrastructure anyway?\n\nAnswering No will direct your browser to Oracle's download page so that you may download the policy files.
\ No newline at end of file +gb.jceWarning = Your Java Runtime Environment does not have the \"JCE Unlimited Strength Jurisdiction Policy\" files.\nThis will limit the length of passwords you may use to encrypt your keystores to 7 characters.\nThese policy files are an optional download from Oracle.\n\nWould you like to continue and generate the certificate infrastructure anyway?\n\nAnswering No will direct your browser to Oracle's download page so that you may download the policy files.
+gb.maxActivityCommits = max activity commits
+gb.maxActivityCommitsDescription = maximum number of commits to contribute to the Activity page
+gb.noMaximum = no maximum
+gb.attributes = attributes
+gb.serveCertificate = serve https with this certificate
+gb.sslCertificateGeneratedRestart = Successfully generated new server SSL certificate for {0}.\nYou must restart Gitblit to use the new certificate.\n\nIf you are launching with the '--alias' parameter you will have to set that to ''--alias {0}''.
+gb.validity = validity
+gb.siteName = site name
+gb.siteNameDescription = short, descriptive name of your server
\ No newline at end of file diff --git a/src/com/gitblit/wicket/pages/CommitPage.java b/src/com/gitblit/wicket/pages/CommitPage.java index b2a8112b..17621ad0 100644 --- a/src/com/gitblit/wicket/pages/CommitPage.java +++ b/src/com/gitblit/wicket/pages/CommitPage.java @@ -169,9 +169,15 @@ public class CommitPage extends RepositoryPage { WicketUtils.newPathParameter(submodulePath, submoduleId, "")).setEnabled(hasSubmodule));
} else {
// blob
- item.add(new LinkPanel("pathName", "list", entry.path, BlobPage.class,
+ String displayPath = entry.path;
+ String path = entry.path;
+ if (entry.isSymlink()) {
+ path = JGitUtils.getStringContent(getRepository(), getCommit().getTree(), path);
+ displayPath = entry.path + " -> " + path;
+ }
+ item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
WicketUtils
- .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ .newPathParameter(repositoryName, entry.commitId, path)));
}
// quick links
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/com/gitblit/wicket/pages/EditRepositoryPage.html index cd3c4662..60893f44 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -39,8 +39,9 @@ <tr><th><wicket:message key="gb.showReadme"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="showReadme" tabindex="10" /> <span class="help-inline"><wicket:message key="gb.showReadmeDescription"></wicket:message></span></label></td></tr>
<tr><th><wicket:message key="gb.skipSizeCalculation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSizeCalculation" tabindex="11" /> <span class="help-inline"><wicket:message key="gb.skipSizeCalculationDescription"></wicket:message></span></label></td></tr>
<tr><th><wicket:message key="gb.skipSummaryMetrics"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSummaryMetrics" tabindex="12" /> <span class="help-inline"><wicket:message key="gb.skipSummaryMetricsDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.maxActivityCommits"></wicket:message></th><td class="edit"><select class="span2" wicket:id="maxActivityCommits" tabindex="13" /> <span class="help-inline"><wicket:message key="gb.maxActivityCommitsDescription"></wicket:message></span></td></tr>
<tr><th colspan="2"><hr/></th></tr>
- <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="mailingLists" size="40" tabindex="13" /></td></tr>
+ <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="mailingLists" size="40" tabindex="14" /></td></tr>
</tbody>
</table>
</div>
@@ -49,15 +50,15 @@ <div class="tab-pane" id="permissions">
<table class="plain">
<tbody class="settings">
- <tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><select class="span2" wicket:id="owner" tabindex="14" /> <span class="help-inline"><wicket:message key="gb.ownerDescription"></wicket:message></span></td></tr>
+ <tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><select class="span2" wicket:id="owner" tabindex="15" /> <span class="help-inline"><wicket:message key="gb.ownerDescription"></wicket:message></span></td></tr>
<tr><th colspan="2"><hr/></th></tr>
- <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="15" /></td></tr>
+ <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="16" /></td></tr>
<tr><th colspan="2"><hr/></th></tr>
<tr><th><wicket:message key="gb.authorizationControl"></wicket:message></th><td style="padding:2px;"><span class="authorizationControl" wicket:id="authorizationControl"></span></td></tr>
<tr><th colspan="2"><hr/></th></tr>
- <tr><th><wicket:message key="gb.isFrozen"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="isFrozen" tabindex="18" /> <span class="help-inline"><wicket:message key="gb.isFrozenDescription"></wicket:message></span></label></td></tr>
- <tr><th><wicket:message key="gb.allowForks"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="allowForks" tabindex="19" /> <span class="help-inline"><wicket:message key="gb.allowForksDescription"></wicket:message></span></label></td></tr>
- <tr><th><wicket:message key="gb.verifyCommitter"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="verifyCommitter" tabindex="20" /> <span class="help-inline"><wicket:message key="gb.verifyCommitterDescription"></wicket:message></span><br/><span class="help-inline" style="padding-left:10px;"><wicket:message key="gb.verifyCommitterNote"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.isFrozen"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="isFrozen" tabindex="17" /> <span class="help-inline"><wicket:message key="gb.isFrozenDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.allowForks"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="allowForks" tabindex="18" /> <span class="help-inline"><wicket:message key="gb.allowForksDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.verifyCommitter"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="verifyCommitter" tabindex="19" /> <span class="help-inline"><wicket:message key="gb.verifyCommitterDescription"></wicket:message></span><br/><span class="help-inline" style="padding-left:10px;"><wicket:message key="gb.verifyCommitterNote"></wicket:message></span></label></td></tr>
<tr><th colspan="2"><hr/></th></tr>
<tr><th><wicket:message key="gb.userPermissions"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr>
<tr><th colspan="2"><hr/></th></tr>
@@ -70,7 +71,7 @@ <div class="tab-pane" id="federation">
<table class="plain">
<tbody class="settings">
- <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="21" /></td></tr>
+ <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="20" /></td></tr>
<tr><th><wicket:message key="gb.federationSets"></wicket:message></th><td style="padding:2px;"><span wicket:id="federationSets"></span></td></tr>
</tbody>
</table>
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java index dead34a9..7f66f688 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -379,7 +379,7 @@ public class EditRepositoryPage extends RootSubPage { form.add(new TextField<String>("description"));
form.add(new DropDownChoice<String>("owner", GitBlit.self().getAllUsernames())
.setEnabled(GitBlitWebSession.get().canAdmin() && !repositoryModel.isPersonalRepository()));
- form.add(new CheckBox("allowForks"));
+ form.add(new CheckBox("allowForks").setEnabled(GitBlit.getBoolean(Keys.web.allowForking, true)));
DropDownChoice<AccessRestrictionType> accessRestriction = new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays
.asList(AccessRestrictionType.values()), new AccessRestrictionRenderer());
form.add(accessRestriction);
@@ -414,6 +414,9 @@ public class EditRepositoryPage extends RootSubPage { form.add(new CheckBox("showReadme"));
form.add(new CheckBox("skipSizeCalculation"));
form.add(new CheckBox("skipSummaryMetrics"));
+ List<Integer> maxActivityCommits = Arrays.asList(0, 25, 50, 75, 100, 150, 200, 250, 500 );
+ form.add(new DropDownChoice<Integer>("maxActivityCommits", maxActivityCommits, new MaxActivityCommitsRenderer()));
+
mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""
: StringUtils.flattenStrings(repositoryModel.mailingLists, " "));
form.add(new TextField<String>("mailingLists", mailingLists));
@@ -654,4 +657,26 @@ public class EditRepositoryPage extends RootSubPage { }
}
+ private class MaxActivityCommitsRenderer implements IChoiceRenderer<Integer> {
+
+ private static final long serialVersionUID = 1L;
+
+ public MaxActivityCommitsRenderer() {
+ }
+
+ @Override
+ public String getDisplayValue(Integer value) {
+ if (value == 0) {
+ return getString("gb.noMaximum");
+ } else {
+ return value + " " + getString("gb.commits");
+ }
+ }
+
+ @Override
+ public String getIdValue(Integer value, int index) {
+ return Integer.toString(index);
+ }
+ }
+
}
diff --git a/src/com/gitblit/wicket/pages/EditTeamPage.java b/src/com/gitblit/wicket/pages/EditTeamPage.java index a22361f1..1991c02a 100644 --- a/src/com/gitblit/wicket/pages/EditTeamPage.java +++ b/src/com/gitblit/wicket/pages/EditTeamPage.java @@ -38,6 +38,7 @@ import org.apache.wicket.model.util.ListModel; import com.gitblit.GitBlit;
import com.gitblit.GitBlitException;
+import com.gitblit.Keys;
import com.gitblit.Constants.RegistrantType;
import com.gitblit.models.RegistrantAccessPermission;
import com.gitblit.models.TeamModel;
@@ -216,7 +217,7 @@ public class EditTeamPage extends RootSubPage { // field names reflective match TeamModel fields
form.add(new TextField<String>("name"));
form.add(new CheckBox("canAdmin"));
- form.add(new CheckBox("canFork"));
+ form.add(new CheckBox("canFork").setEnabled(GitBlit.getBoolean(Keys.web.allowForking, true)));
form.add(new CheckBox("canCreate"));
form.add(users.setEnabled(editMemberships));
mailingLists = new Model<String>(teamModel.mailingLists == null ? ""
diff --git a/src/com/gitblit/wicket/pages/EditUserPage.html b/src/com/gitblit/wicket/pages/EditUserPage.html index e697a354..e79011c8 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.html +++ b/src/com/gitblit/wicket/pages/EditUserPage.html @@ -13,6 +13,7 @@ <!-- tab titles -->
<ul class="nav nav-tabs">
<li class="active"><a href="#general" data-toggle="tab"><wicket:message key="gb.general"></wicket:message></a></li>
+ <li><a href="#attributes" data-toggle="tab"><wicket:message key="gb.attributes"></wicket:message></a></li>
<li><a href="#permissions" data-toggle="tab"><wicket:message key="gb.accessPermissions"></wicket:message></a></li>
</ul>
@@ -36,6 +37,19 @@ </table>
</div>
+ <!-- attributes tab -->
+ <div class="tab-pane" id="attributes">
+ <table class="plain">
+ <tbody class="settings">
+ <tr><th><wicket:message key="gb.organizationalUnit"></wicket:message> (OU)</th><td class="edit"><input type="text" wicket:id="organizationalUnit" size="30" tabindex="1" /></td></tr>
+ <tr><th><wicket:message key="gb.organization"></wicket:message> (O)</th><td class="edit"><input type="text" wicket:id="organization" size="30" tabindex="2" /></td></tr>
+ <tr><th><wicket:message key="gb.locality"></wicket:message> (L)</th><td class="edit"><input type="text" wicket:id="locality" size="30" tabindex="3" /></td></tr>
+ <tr><th><wicket:message key="gb.stateProvince"></wicket:message> (ST)</th><td class="edit"><input type="text" wicket:id="stateProvince" size="30" tabindex="4" /></td></tr>
+ <tr><th><wicket:message key="gb.countryCode"></wicket:message> (C)</th><td class="edit"><input type="text" wicket:id="countryCode" size="15 " tabindex="5" /></td></tr>
+ </tbody>
+ </table>
+ </div>
+
<!-- access permissions tab -->
<div class="tab-pane" id="permissions">
<table class="plain">
diff --git a/src/com/gitblit/wicket/pages/EditUserPage.java b/src/com/gitblit/wicket/pages/EditUserPage.java index 80f09dba..7a01fb68 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.java +++ b/src/com/gitblit/wicket/pages/EditUserPage.java @@ -233,12 +233,17 @@ public class EditUserPage extends RootSubPage { form.add(new TextField<String>("displayName").setEnabled(editDisplayName));
form.add(new TextField<String>("emailAddress").setEnabled(editEmailAddress));
form.add(new CheckBox("canAdmin"));
- form.add(new CheckBox("canFork"));
+ form.add(new CheckBox("canFork").setEnabled(GitBlit.getBoolean(Keys.web.allowForking, true)));
form.add(new CheckBox("canCreate"));
form.add(new CheckBox("excludeFromFederation"));
form.add(new RegistrantPermissionsPanel("repositories", RegistrantType.REPOSITORY, repos, permissions, getAccessPermissions()));
form.add(teams.setEnabled(editTeams));
+ form.add(new TextField<String>("organizationalUnit").setEnabled(editDisplayName));
+ form.add(new TextField<String>("organization").setEnabled(editDisplayName));
+ form.add(new TextField<String>("locality").setEnabled(editDisplayName));
+ form.add(new TextField<String>("stateProvince").setEnabled(editDisplayName));
+ form.add(new TextField<String>("countryCode").setEnabled(editDisplayName));
form.add(new Button("save"));
Button cancel = new Button("cancel") {
private static final long serialVersionUID = 1L;
diff --git a/src/com/gitblit/wicket/pages/RepositoryPage.java b/src/com/gitblit/wicket/pages/RepositoryPage.java index 346edc3e..3acf73af 100644 --- a/src/com/gitblit/wicket/pages/RepositoryPage.java +++ b/src/com/gitblit/wicket/pages/RepositoryPage.java @@ -154,7 +154,9 @@ public abstract class RepositoryPage extends BasePage { pages.put("branches", new PageRegistration("gb.branches", BranchesPage.class, params));
pages.put("tags", new PageRegistration("gb.tags", TagsPage.class, params));
pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
- pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));
+ if (GitBlit.getBoolean(Keys.web.allowForking, true)) {
+ pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));
+ }
// conditional links
Repository r = getRepository();
@@ -191,7 +193,7 @@ public abstract class RepositoryPage extends BasePage { }
protected boolean allowForkControls() {
- return true;
+ return GitBlit.getBoolean(Keys.web.allowForking, true);
}
@Override
@@ -597,4 +599,4 @@ public abstract class RepositoryPage extends BasePage { getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
}
}
-} +}
diff --git a/src/com/gitblit/wicket/pages/TreePage.java b/src/com/gitblit/wicket/pages/TreePage.java index 345814f4..b8ce7b48 100644 --- a/src/com/gitblit/wicket/pages/TreePage.java +++ b/src/com/gitblit/wicket/pages/TreePage.java @@ -144,25 +144,31 @@ public class TreePage extends RepositoryPage { item.add(links);
} else {
// blob link
+ String displayPath = entry.name;
+ String path = entry.path;
+ if (entry.isSymlink()) {
+ path = JGitUtils.getStringContent(getRepository(), getCommit().getTree(), path);
+ displayPath = entry.name + " -> " + path;
+ }
item.add(WicketUtils.getFileImage("pathIcon", entry.name));
item.add(new Label("pathSize", byteFormat.format(entry.size)));
- item.add(new LinkPanel("pathName", "list", entry.name, BlobPage.class,
+ item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
WicketUtils.newPathParameter(repositoryName, entry.commitId,
- entry.path)));
+ path)));
// links
Fragment links = new Fragment("pathLinks", "blobLinks", this);
links.add(new BookmarkablePageLink<Void>("view", BlobPage.class,
WicketUtils.newPathParameter(repositoryName, entry.commitId,
- entry.path)));
+ path)));
links.add(new BookmarkablePageLink<Void>("raw", RawPage.class, WicketUtils
- .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ .newPathParameter(repositoryName, entry.commitId, path)));
links.add(new BookmarkablePageLink<Void>("blame", BlamePage.class,
WicketUtils.newPathParameter(repositoryName, entry.commitId,
- entry.path)));
+ path)));
links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class,
WicketUtils.newPathParameter(repositoryName, entry.commitId,
- entry.path)));
+ path)));
item.add(links);
}
}
|