From 58d93319bd870c93d16764b86a4163ac2d1f0561 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 3 Dec 2012 16:55:19 -0500 Subject: Fixed branch view regression (issue-175) --- src/com/gitblit/models/UserModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/com/gitblit') 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 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) { -- cgit v1.2.3 From 37fa664c58df034607edf2485a1414b3417b2755 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 3 Dec 2012 16:59:17 -0500 Subject: Consolidate authentication techniques and support container principals (issue-68) --- docs/04_releases.mkd | 6 +- src/com/gitblit/AuthenticationFilter.java | 43 +------------ src/com/gitblit/Constants.java | 2 +- src/com/gitblit/GitBlit.java | 103 +++++++++++++++++++++++++----- 4 files changed, 94 insertions(+), 60 deletions(-) (limited to 'src/com/gitblit') diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd index 3f03160a..bf57d118 100644 --- a/docs/04_releases.mkd +++ b/docs/04_releases.mkd @@ -72,7 +72,7 @@ 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. +- 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 +83,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 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..02906ee9 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; } -- cgit v1.2.3 From d3c18925529690716ce1b9038169d7a07e53b287 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 3 Dec 2012 17:03:31 -0500 Subject: Set subjectAlternativeName on SSL cert if CN=IPAddress (issue-170) --- docs/04_releases.mkd | 1 + src/com/gitblit/utils/HttpUtils.java | 22 ++++++++++++++++++++++ src/com/gitblit/utils/X509Utils.java | 12 ++++++++++++ 3 files changed, 35 insertions(+) (limited to 'src/com/gitblit') diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd index bf57d118..2f351822 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) diff --git a/src/com/gitblit/utils/HttpUtils.java b/src/com/gitblit/utils/HttpUtils.java index b40088c8..56c8bd20 100644 --- a/src/com/gitblit/utils/HttpUtils.java +++ b/src/com/gitblit/utils/HttpUtils.java @@ -178,4 +178,26 @@ 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; + } + } + } + // 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 altNames = new ArrayList(); + 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) -- cgit v1.2.3 From f3edc279212106215ee40314f48db2f39ce1b631 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 3 Dec 2012 17:04:07 -0500 Subject: Update to MarkdownPapers 1.3.2 --- .classpath | 2 +- gitblit.iml | 28 +++++++++++++++++++++++++--- src/com/gitblit/build/Build.java | 8 ++++---- 3 files changed, 30 insertions(+), 8 deletions(-) (limited to 'src/com/gitblit') diff --git a/.classpath b/.classpath index 55018bfb..e4824fb9 100644 --- a/.classpath +++ b/.classpath @@ -20,7 +20,7 @@ - + diff --git a/gitblit.iml b/gitblit.iml index 12f69f38..caf00726 100644 --- a/gitblit.iml +++ b/gitblit.iml @@ -196,13 +196,13 @@ - + - + - + @@ -347,6 +347,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/gitblit/build/Build.java b/src/com/gitblit/build/Build.java index e8e6b45d..3bfe680d 100644 --- a/src/com/gitblit/build/Build.java +++ b/src/com/gitblit/build/Build.java @@ -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( -- cgit v1.2.3 From 2e8c48c0048e386431d5c41cea733b6d95760d52 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 3 Dec 2012 17:05:49 -0500 Subject: Update to Jetty 7.6.8 --- .classpath | 4 ++-- gitblit.iml | 12 ++++++------ src/com/gitblit/build/Build.java | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src/com/gitblit') diff --git a/.classpath b/.classpath index e4824fb9..498678bb 100644 --- a/.classpath +++ b/.classpath @@ -9,8 +9,8 @@ - - + + diff --git a/gitblit.iml b/gitblit.iml index caf00726..7f21c49a 100644 --- a/gitblit.iml +++ b/gitblit.iml @@ -77,24 +77,24 @@ - + - + - + - + - + - + diff --git a/src/com/gitblit/build/Build.java b/src/com/gitblit/build/Build.java index 3bfe680d..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( -- cgit v1.2.3 From 1d9ac51db01b654f2c97d9fd3057b7b0ed716b91 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 3 Dec 2012 17:06:28 -0500 Subject: Simplified archive generation (issue-174) --- src/com/gitblit/utils/CompressionUtils.java | 88 +++++++++++------------------ 1 file changed, 32 insertions(+), 56 deletions(-) (limited to 'src/com/gitblit') diff --git a/src/com/gitblit/utils/CompressionUtils.java b/src/com/gitblit/utils/CompressionUtils.java index 7b0d0471..41451906 100644 --- a/src/com/gitblit/utils/CompressionUtils.java +++ b/src/com/gitblit/utils/CompressionUtils.java @@ -15,27 +15,24 @@ */ 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.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 +96,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 +245,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,45 +255,25 @@ public class CompressionUtils { tw.setFilter(f); } tw.setRecursive(true); + MutableObjectId id = new MutableObjectId(); + ObjectReader reader = tw.getObjectReader(); + 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); + tw.getObjectId(id, 0); - // new entry TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString()); - entry.setSize(tw.getObjectReader().getObjectSize(id, Constants.OBJ_BLOB)); + entry.setSize(reader.getObjectSize(id, Constants.OBJ_BLOB)); - 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")); - } else { - // regular file or executable file - entry.setMode(mode.getBits()); - } - entry.setModTime(commit.getAuthorIdent().getWhen()); - + entry.setMode(mode.getBits()); + entry.setModTime(modified); 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); - } - - // close entry + ObjectLoader ldr = repository.open(id); + ldr.copyTo(tos); tos.closeArchiveEntry(); } tos.finish(); -- cgit v1.2.3 From e5662e85681deb98e2ed65831ade3f066f29f154 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 3 Dec 2012 17:20:17 -0500 Subject: Support symlink display in tree and commit pages (issue-171) --- docs/04_releases.mkd | 231 ++++++++++++++------------- src/com/gitblit/models/PathModel.java | 4 + src/com/gitblit/wicket/pages/CommitPage.java | 10 +- src/com/gitblit/wicket/pages/TreePage.java | 18 ++- 4 files changed, 140 insertions(+), 123 deletions(-) (limited to 'src/com/gitblit') diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd index 2f351822..7dd4e747 100644 --- a/docs/04_releases.mkd +++ b/docs/04_releases.mkd @@ -27,41 +27,41 @@ The permissions model has changed in this release. #### additions -- Implemented discrete repository permissions (issue 36) +- Implemented discrete repository permissions (issue 36) - V (view in web ui, RSS feeds, download zip) - R (clone) - 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) +- 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) +- 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 however 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. -- Added optional *create-on-push* support - **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* - **New:** *git.defaultGarbageCollectionThreshold = 500k* +- Added optional *create-on-push* support + **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* + **New:** *git.defaultGarbageCollectionThreshold = 500k* **New:** *git.defaultGarbageCollectionPeriod = 7 days* -- Added support for X509 client certificate authentication (github/kevinanderson1). (issue 106) -You can require all git servlet access be authenticated by a client certificate. You may also specify the OID fingerprint to use for mapping a certificate to a username. It should be noted that the user account MUST already exist in Gitblit for this authentication mechanism to work; this mechanism can not be used to automatically create user accounts from a certificate. - **New:** *git.requireClientCertificates = false* - **New:** *git.enforceCertificateValidity = true* +- Added support for X509 client certificate authentication (github/kevinanderson1). (issue 106) +You can require all git servlet access be authenticated by a client certificate. You may also specify the OID fingerprint to use for mapping a certificate to a username. It should be noted that the user account MUST already exist in Gitblit for this authentication mechanism to work; this mechanism can not be used to automatically create user accounts from a certificate. + **New:** *git.requireClientCertificates = false* + **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. The store files have been renamed! -- 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. +- 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 setting to control length of shortened commit ids - **New:** *web.shortCommitIdLength=8* -- Added alternate compressed download formats: tar.gz, tar.xz, tar.bzip2 (issue 174) +- Added setting to control length of shortened commit ids + **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*. - Added support for X-Forwarded-Context for Apache subdomain proxy configurations (issue 135) @@ -73,6 +73,7 @@ This is extreme and should be considered carefully since it affects every https #### changes +- 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) @@ -82,7 +83,7 @@ This is extreme and should be considered carefully since it affects every https - Expose ReceivePack to Groovy push hooks (issue 125) - Redirect to summary page when refreshing the empty repository page on a repository that is not empty (issue 129) - 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. +- 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) @@ -116,8 +117,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) @@ -131,25 +132,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) @@ -178,38 +179,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) @@ -274,32 +275,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) @@ -308,7 +309,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) @@ -344,31 +345,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 however 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 however 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) @@ -378,7 +379,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 @@ -390,7 +391,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)
@@ -398,25 +399,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) @@ -433,15 +434,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 @@ -461,9 +462,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/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 { 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/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/TreePage.java b/src/com/gitblit/wicket/pages/TreePage.java index 345814f4..5396ed6c 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.path; + String path = entry.path; + if (entry.isSymlink()) { + path = JGitUtils.getStringContent(getRepository(), getCommit().getTree(), path); + displayPath = entry.path + " -> " + 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("view", BlobPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, - entry.path))); + path))); links.add(new BookmarkablePageLink("raw", RawPage.class, WicketUtils - .newPathParameter(repositoryName, entry.commitId, entry.path))); + .newPathParameter(repositoryName, entry.commitId, path))); links.add(new BookmarkablePageLink("blame", BlamePage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, - entry.path))); + path))); links.add(new BookmarkablePageLink("history", HistoryPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, - entry.path))); + path))); item.add(links); } } -- cgit v1.2.3 From 8ee931e0a051b73c1128e8fa73ead9084c6d2e09 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 3 Dec 2012 21:29:32 -0500 Subject: Fixes to symlink handling (issue-174) --- src/com/gitblit/utils/CompressionUtils.java | 30 ++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'src/com/gitblit') diff --git a/src/com/gitblit/utils/CompressionUtils.java b/src/com/gitblit/utils/CompressionUtils.java index 41451906..a8dcdd8f 100644 --- a/src/com/gitblit/utils/CompressionUtils.java +++ b/src/com/gitblit/utils/CompressionUtils.java @@ -27,6 +27,7 @@ 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.wicket.util.io.ByteArrayOutputStream; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.MutableObjectId; @@ -256,7 +257,6 @@ public class CompressionUtils { } tw.setRecursive(true); MutableObjectId id = new MutableObjectId(); - ObjectReader reader = tw.getObjectReader(); long modified = commit.getAuthorIdent().getWhen().getTime(); while (tw.next()) { FileMode mode = tw.getFileMode(0); @@ -265,16 +265,24 @@ public class CompressionUtils { } tw.getObjectId(id, 0); - TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString()); - entry.setSize(reader.getObjectSize(id, Constants.OBJ_BLOB)); - - entry.setMode(mode.getBits()); - entry.setModTime(modified); - tos.putArchiveEntry(entry); - - ObjectLoader ldr = repository.open(id); - ldr.copyTo(tos); - tos.closeArchiveEntry(); + 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 { + TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString()); + entry.setMode(mode.getBits()); + entry.setModTime(modified); + entry.setSize(loader.getSize()); + tos.putArchiveEntry(entry); + loader.copyTo(tos); + tos.closeArchiveEntry(); + } } tos.finish(); tos.close(); -- cgit v1.2.3 From 7670a00feb789cd4bd16d87144f6f94adb1f43db Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 4 Dec 2012 11:17:08 -0500 Subject: Fixed regresion in path name display in tree page --- src/com/gitblit/wicket/pages/TreePage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/com/gitblit') diff --git a/src/com/gitblit/wicket/pages/TreePage.java b/src/com/gitblit/wicket/pages/TreePage.java index 5396ed6c..b8ce7b48 100644 --- a/src/com/gitblit/wicket/pages/TreePage.java +++ b/src/com/gitblit/wicket/pages/TreePage.java @@ -144,11 +144,11 @@ public class TreePage extends RepositoryPage { item.add(links); } else { // blob link - String displayPath = entry.path; + String displayPath = entry.name; String path = entry.path; if (entry.isSymlink()) { path = JGitUtils.getStringContent(getRepository(), getCommit().getTree(), path); - displayPath = entry.path + " -> " + path; + displayPath = entry.name + " -> " + path; } item.add(WicketUtils.getFileImage("pathIcon", entry.name)); item.add(new Label("pathSize", byteFormat.format(entry.size))); -- cgit v1.2.3 From 428b2244aadeb4724e705044d73ac74be724f6e9 Mon Sep 17 00:00:00 2001 From: mschaefers Date: Tue, 4 Dec 2012 16:07:37 -0500 Subject: Merged and enhanced pull request #55 (disallow forks setting) --- distrib/gitblit.properties | 8 +++++++- src/com/gitblit/wicket/pages/EditRepositoryPage.java | 2 +- src/com/gitblit/wicket/pages/EditTeamPage.java | 3 ++- src/com/gitblit/wicket/pages/EditUserPage.java | 2 +- src/com/gitblit/wicket/pages/RepositoryPage.java | 8 +++++--- 5 files changed, 16 insertions(+), 7 deletions(-) (limited to 'src/com/gitblit') diff --git a/distrib/gitblit.properties b/distrib/gitblit.properties index 233fdfad..d57f9ba1 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 @@ -1179,4 +1185,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/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java index dead34a9..9de8244a 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("description")); form.add(new DropDownChoice("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 accessRestriction = new DropDownChoice("accessRestriction", Arrays .asList(AccessRestrictionType.values()), new AccessRestrictionRenderer()); form.add(accessRestriction); 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("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(teamModel.mailingLists == null ? "" diff --git a/src/com/gitblit/wicket/pages/EditUserPage.java b/src/com/gitblit/wicket/pages/EditUserPage.java index 80f09dba..d22800ef 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.java +++ b/src/com/gitblit/wicket/pages/EditUserPage.java @@ -233,7 +233,7 @@ public class EditUserPage extends RootSubPage { form.add(new TextField("displayName").setEnabled(editDisplayName)); form.add(new TextField("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())); 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)); } } -} +} -- cgit v1.2.3 From 8295dd6cab32df383a30e4bd78e4aff17cfa2187 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 5 Dec 2012 17:20:06 -0500 Subject: Global and per-repository setting to throttle prolific repos in Activity page (issue-173) --- distrib/gitblit.properties | 8 +++++++ docs/04_releases.mkd | 1 + src/com/gitblit/GitBlit.java | 14 +++++++++++- src/com/gitblit/client/EditRepositoryDialog.java | 9 ++++++++ src/com/gitblit/models/RepositoryModel.java | 1 + src/com/gitblit/utils/ActivityUtils.java | 6 +++++- src/com/gitblit/wicket/GitBlitWebApp.properties | 5 ++++- .../gitblit/wicket/pages/EditRepositoryPage.html | 15 +++++++------ .../gitblit/wicket/pages/EditRepositoryPage.java | 25 ++++++++++++++++++++++ 9 files changed, 74 insertions(+), 10 deletions(-) (limited to 'src/com/gitblit') diff --git a/distrib/gitblit.properties b/distrib/gitblit.properties index d57f9ba1..e3d72211 100644 --- a/distrib/gitblit.properties +++ b/distrib/gitblit.properties @@ -522,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 diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd index 7dd4e747..52bd51e7 100644 --- a/docs/04_releases.mkd +++ b/docs/04_releases.mkd @@ -73,6 +73,7 @@ This is extreme and should be considered carefully since it affects every https #### changes +- 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* diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index 02906ee9..c2d4a85a 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -1602,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('\\', '/'); @@ -2068,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/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/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 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/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index 6ee12990..9ee9f397 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -430,4 +430,7 @@ 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 \ No newline at end of file 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 @@ + + @@ -49,15 +50,15 @@
- + - + - - - + + + @@ -70,7 +71,7 @@





- +
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java index 9de8244a..7f66f688 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -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 maxActivityCommits = Arrays.asList(0, 25, 50, 75, 100, 150, 200, 250, 500 ); + form.add(new DropDownChoice("maxActivityCommits", maxActivityCommits, new MaxActivityCommitsRenderer())); + mailingLists = new Model(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? "" : StringUtils.flattenStrings(repositoryModel.mailingLists, " ")); form.add(new TextField("mailingLists", mailingLists)); @@ -654,4 +657,26 @@ public class EditRepositoryPage extends RootSubPage { } } + private class MaxActivityCommitsRenderer implements IChoiceRenderer { + + 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); + } + } + } -- cgit v1.2.3 From 6929d9df029d230d45d2b3f33717cb0ae6a40c56 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 5 Dec 2012 17:24:18 -0500 Subject: Added attributes tab to Edit User for both site and Manager --- src/com/gitblit/client/EditUserDialog.java | 39 +++++++++++++++++++++++++ src/com/gitblit/wicket/GitBlitWebApp.properties | 3 +- src/com/gitblit/wicket/pages/EditUserPage.html | 14 +++++++++ src/com/gitblit/wicket/pages/EditUserPage.java | 5 ++++ 4 files changed, 60 insertions(+), 1 deletion(-) (limited to 'src/com/gitblit') 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 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(); @@ -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/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index 9ee9f397..7ce75262 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -433,4 +433,5 @@ 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. gb.maxActivityCommits = max activity commits gb.maxActivityCommitsDescription = maximum number of commits to contribute to the Activity page -gb.noMaximum = no maximum \ No newline at end of file +gb.noMaximum = no maximum +gb.attributes = attributes \ No newline at end of file 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 @@ @@ -36,6 +37,19 @@
+ +
+ + + + + + + + +
(OU)
(O)
(L)
(ST)
(C)
+
+
diff --git a/src/com/gitblit/wicket/pages/EditUserPage.java b/src/com/gitblit/wicket/pages/EditUserPage.java index d22800ef..7a01fb68 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.java +++ b/src/com/gitblit/wicket/pages/EditUserPage.java @@ -239,6 +239,11 @@ public class EditUserPage extends RootSubPage { form.add(new RegistrantPermissionsPanel("repositories", RegistrantType.REPOSITORY, repos, permissions, getAccessPermissions())); form.add(teams.setEnabled(editTeams)); + form.add(new TextField("organizationalUnit").setEnabled(editDisplayName)); + form.add(new TextField("organization").setEnabled(editDisplayName)); + form.add(new TextField("locality").setEnabled(editDisplayName)); + form.add(new TextField("stateProvince").setEnabled(editDisplayName)); + form.add(new TextField("countryCode").setEnabled(editDisplayName)); form.add(new Button("save")); Button cancel = new Button("cancel") { private static final long serialVersionUID = 1L; -- cgit v1.2.3 From e521a7d031fab2655ec6f8eba9876829a4d300b2 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 5 Dec 2012 17:24:59 -0500 Subject: Fixed validate IPv4 address method --- src/com/gitblit/utils/HttpUtils.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/com/gitblit') diff --git a/src/com/gitblit/utils/HttpUtils.java b/src/com/gitblit/utils/HttpUtils.java index 56c8bd20..86f53cfe 100644 --- a/src/com/gitblit/utils/HttpUtils.java +++ b/src/com/gitblit/utils/HttpUtils.java @@ -196,6 +196,7 @@ public class HttpUtils { return false; } } + return true; } // TODO IPV6? return false; -- cgit v1.2.3 From acb63a082e9497e3a1e2541f5e44587eada7c60b Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 5 Dec 2012 17:29:39 -0500 Subject: Added server setting to specify keystore alias for ssl certificate (issue 98) --- distrib/gitblit.properties | 7 +++++++ docs/04_releases.mkd | 1 + src/com/gitblit/GitBlitServer.java | 12 ++++++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/com/gitblit') diff --git a/distrib/gitblit.properties b/distrib/gitblit.properties index e3d72211..ce269d2c 100644 --- a/distrib/gitblit.properties +++ b/distrib/gitblit.properties @@ -1155,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 diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd index 52bd51e7..ef8a1446 100644 --- a/docs/04_releases.mkd +++ b/docs/04_releases.mkd @@ -73,6 +73,7 @@ This is extreme and should be considered carefully since it affects every https #### changes +- 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. diff --git a/src/com/gitblit/GitBlitServer.java b/src/com/gitblit/GitBlitServer.java index d98f8916..5eaa4c90 100644 --- a/src/com/gitblit/GitBlitServer.java +++ b/src/com/gitblit/GitBlitServer.java @@ -242,7 +242,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 +413,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,7 +423,7 @@ 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); @@ -466,6 +467,10 @@ public class GitBlitServer { sslContext.setTrustStore(clientTrustStore.getAbsolutePath()); sslContext.setTrustStorePassword(storePassword); sslContext.setCrlPath(caRevocationList.getAbsolutePath()); + if (!StringUtils.isEmpty(certAlias)) { + logger.info(" certificate alias = " + certAlias); + sslContext.setCertAlias(certAlias); + } connector.setPort(port); connector.setMaxIdleTime(30000); return connector; @@ -596,6 +601,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, ""); -- cgit v1.2.3 From d63157b22bb8a7294080be29ca0fca8ecda96db9 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 5 Dec 2012 17:36:16 -0500 Subject: Checkbox to automatically set the new ssl certificate alias --- src/com/gitblit/authority/GitblitAuthority.java | 21 ++++++++++++++++++--- .../gitblit/authority/NewSSLCertificateDialog.java | 12 +++++++++++- src/com/gitblit/wicket/GitBlitWebApp.properties | 4 +++- 3 files changed, 32 insertions(+), 5 deletions(-) (limited to 'src/com/gitblit') diff --git a/src/com/gitblit/authority/GitblitAuthority.java b/src/com/gitblit/authority/GitblitAuthority.java index d97a8e39..59cd22e3 100644 --- a/src/com/gitblit/authority/GitblitAuthority.java +++ b/src/com/gitblit/authority/GitblitAuthority.java @@ -607,7 +607,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 +624,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 updates = new HashMap(); + 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); + } } }; 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/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index 7ce75262..4f4d60e0 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -434,4 +434,6 @@ gb.jceWarning = Your Java Runtime Environment does not have the \"JCE Unlimited gb.maxActivityCommits = max activity commits gb.maxActivityCommitsDescription = maximum number of commits to contribute to the Activity page gb.noMaximum = no maximum -gb.attributes = attributes \ No newline at end of file +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}''. \ No newline at end of file -- cgit v1.2.3 From 6c127c1ce12994ab4a235c53c254cf776e347e69 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 5 Dec 2012 17:39:11 -0500 Subject: Improving first-run setup of GCA and Gitblit GO --- src/com/gitblit/authority/GitblitAuthority.java | 34 +++++++++++++++++++------ src/com/gitblit/wicket/GitBlitWebApp.properties | 5 +++- 2 files changed, 30 insertions(+), 9 deletions(-) (limited to 'src/com/gitblit') diff --git a/src/com/gitblit/authority/GitblitAuthority.java b/src/com/gitblit/authority/GitblitAuthority.java index 59cd22e3..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 updates = new HashMap(); + updates.put(Keys.web.siteName, siteNameTF.getText()); + gitblitSettings.saveSettings(updates); } catch (Exception e1) { Utils.showException(GitblitAuthority.this, e1); } @@ -728,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/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index 4f4d60e0..5b42a2c0 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -436,4 +436,7 @@ gb.maxActivityCommitsDescription = maximum number of commits to contribute to th 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}''. \ No newline at end of file +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 -- cgit v1.2.3 From 6db4261a984da3d70cd3ac35869f19a75edc0ce8 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 5 Dec 2012 19:05:59 -0500 Subject: Implemented hot-reloadable CRL --- src/com/gitblit/GitBlitServer.java | 40 ++------- src/com/gitblit/GitblitSslContextFactory.java | 94 +++++++++++++++++++ src/com/gitblit/GitblitTrustManager.java | 125 ++++++++++++++++++++++++++ 3 files changed, 226 insertions(+), 33 deletions(-) create mode 100644 src/com/gitblit/GitblitSslContextFactory.java create mode 100644 src/com/gitblit/GitblitTrustManager.java (limited to 'src/com/gitblit') diff --git a/src/com/gitblit/GitBlitServer.java b/src/com/gitblit/GitBlitServer.java index 5eaa4c90..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; @@ -426,53 +425,28 @@ public class GitBlitServer { 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()); - if (!StringUtils.isEmpty(certAlias)) { - logger.info(" certificate alias = " + certAlias); - sslContext.setCertAlias(certAlias); - } connector.setPort(port); connector.setMaxIdleTime(30000); + return connector; } 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 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 -- cgit v1.2.3