diff options
author | Florian Zschocke <f.zschocke+git@gmail.com> | 2022-03-13 18:03:17 +0100 |
---|---|---|
committer | Florian Zschocke <f.zschocke+git@gmail.com> | 2022-03-13 18:03:17 +0100 |
commit | 9b4afad6f4be212474809533ec2c280cce86501a (patch) | |
tree | 9dbdc1fe354efc77330589a52b75aedb49ab1428 /src/test/java | |
parent | 16ec6d07c58356d9b20652b5ae168ae9f0fd2eaa (diff) | |
download | gitblit-9b4afad6f4be212474809533ec2c280cce86501a.tar.gz gitblit-9b4afad6f4be212474809533ec2c280cce86501a.zip |
fix: Fix StoredUserConfig not escaping control characters
The `StoredUserConfig` only escaped the escape character, i.e. backslash.
But it does not escape control characters like tab or newline. This
introduces a vulnerability where an attacker can create new entries
in their user account and create new accounts.
In addition, other characters are also not properly handled. Field values
with a comment character need to be quoted. This only happens for the
`#` character and only when the value starts with it. Also the quote
is note escaped in values.
This change completely rewrites the `escape` method of `StoredUserConfig`.
It takes care of properly escaping characters that need escaping for the
git configuration file format.
This fixes #1410
Diffstat (limited to 'src/test/java')
-rw-r--r-- | src/test/java/com/gitblit/StoredUserConfigTest.java | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/src/test/java/com/gitblit/StoredUserConfigTest.java b/src/test/java/com/gitblit/StoredUserConfigTest.java index 01964617..012139d3 100644 --- a/src/test/java/com/gitblit/StoredUserConfigTest.java +++ b/src/test/java/com/gitblit/StoredUserConfigTest.java @@ -55,4 +55,153 @@ public class StoredUserConfigTest assertEquals("noone", cfg.getString("TEAM", null, "displayName")); } + + @Test + public void testStringFields() throws Exception + { + StoredUserConfig config = new StoredUserConfig(file); + config.setString("USER", "admin", "password", "secret"); + config.setString("USER", "admin", "displayName", "marusha"); + config.setString("USER", "admin", "email", "name@example.com"); + + config.setString("USER", "other", "password", "password"); + config.setString("USER", "other", "displayName", "mama"); + config.setString("USER", "other", "email", "other@example.com"); + config.setString("USER", "other", "repository", "RW+:repo1"); + config.setString("USER", "other", "repository", "RW+:repo2"); + + config.setString("USER", null, "displayName", "default"); + + config.save(); + + StoredConfig cfg = new FileBasedConfig(file, FS.detect()); + cfg.load(); + assertEquals("secret", cfg.getString("USER", "admin", "password")); + assertEquals("marusha", cfg.getString("USER", "admin", "displayName")); + assertEquals("name@example.com", cfg.getString("USER", "admin", "email")); + + assertEquals("password", cfg.getString("USER", "other", "password")); + assertEquals("mama", cfg.getString("USER", "other", "displayName")); + assertEquals("other@example.com", cfg.getString("USER", "other", "email")); + + String[] stringList = cfg.getStringList("USER", "other", "repository"); + assertNotNull(stringList); + assertEquals(2, stringList.length); + int i = 0; + for (String s : stringList) { + if (s.equalsIgnoreCase("RW+:repo1")) i += 1; + else if (s.equalsIgnoreCase("RW+:repo2")) i += 2; + } + assertEquals("Not all repository strings found", 3, i); + + assertEquals("default", cfg.getString("USER", null, "displayName")); + } + + + @Test + public void testBooleanFields() throws Exception + { + StoredUserConfig config = new StoredUserConfig(file); + config.setBoolean("USER", "admin", "emailMeOnMyTicketChanges", true); + config.setBoolean("USER", "master", "emailMeOnMyTicketChanges", false); + config.setBoolean("TEAM", "admin", "excludeFromFederation", true); + config.setBoolean("USER", null, "excludeFromFederation", false); + + config.save(); + + StoredConfig cfg = new FileBasedConfig(file, FS.detect()); + cfg.load(); + assertTrue(cfg.getBoolean("USER", "admin", "emailMeOnMyTicketChanges", false)); + assertFalse(cfg.getBoolean("USER", "master", "emailMeOnMyTicketChanges", true)); + assertTrue(cfg.getBoolean("TEAM", "admin", "excludeFromFederation", false)); + assertFalse(cfg.getBoolean("USER", null, "excludeFromFederation", true)); + } + + + @Test + public void testHashEscape() throws Exception + { + StoredUserConfig config = new StoredUserConfig(file); + config.setString("USER", "admin", "role", "#admin"); + + config.setString("USER", "other", "role", "#none"); + config.setString("USER", "other", "displayName", "big#"); + config.setString("USER", "other", "email", "user#name@home.de"); + + config.save(); + + StoredConfig cfg = new FileBasedConfig(file, FS.detect()); + cfg.load(); + assertEquals("#admin", cfg.getString("USER", "admin", "role")); + assertEquals("#none", cfg.getString("USER", "other", "role")); + assertEquals("big#", cfg.getString("USER", "other", "displayName")); + assertEquals("user#name@home.de", cfg.getString("USER", "other", "email")); + } + + + @Test + public void testCtrlEscape() throws Exception + { + StoredUserConfig config = new StoredUserConfig(file); + config.setString("USER", "name", "password", "bing\bbong"); + config.setString("USER", "name", "role", "domain\\admin"); + config.setString("USER", "name", "displayName", "horny\n\telephant"); + config.setString("USER", "name", "org", "\tbig\tblue"); + config.setString("USER", "name", "unit", "the end\n"); + + config.setString("USER", null, "unit", "the\ndefault"); + + config.save(); + + StoredConfig cfg = new FileBasedConfig(file, FS.detect()); + cfg.load(); + assertEquals("bing\bbong", cfg.getString("USER", "name", "password")); + assertEquals("domain\\admin", cfg.getString("USER", "name", "role")); + assertEquals("horny\n\telephant", cfg.getString("USER", "name", "displayName")); + assertEquals("\tbig\tblue", cfg.getString("USER", "name", "org")); + assertEquals("the end\n", cfg.getString("USER", "name", "unit")); + + assertEquals("the\ndefault", cfg.getString("USER", null, "unit")); + } + + + @Test + public void testQuoteEscape() throws Exception + { + StoredUserConfig config = new StoredUserConfig(file); + config.setString("USER", "dude", "password", "going\"places"); + config.setString("USER", "dude", "role", "\"dude\""); + config.setString("USER", "dude", "displayName", "John \"The Dude\" Lebowski"); + config.setString("USER", "dude", "repo", "\"front matter"); + config.setString("USER", "dude", "peepo", "leadout\""); + + config.save(); + + StoredConfig cfg = new FileBasedConfig(file, FS.detect()); + cfg.load(); + assertEquals("going\"places", cfg.getString("USER", "dude", "password")); + assertEquals("\"dude\"", cfg.getString("USER", "dude", "role")); + assertEquals("John \"The Dude\" Lebowski", cfg.getString("USER", "dude", "displayName")); + assertEquals("\"front matter", cfg.getString("USER", "dude", "repo")); + assertEquals("leadout\"", cfg.getString("USER", "dude", "peepo")); + } + + + @Test + public void testUTF8() throws Exception + { + StoredUserConfig config = new StoredUserConfig(file); + config.setString("USER", "ming", "password", "一\t二\n三"); + config.setString("USER", "ming", "displayName", "白老鼠"); + config.setString("USER", "ming", "peepo", "Mickey \"白老鼠\" Whitfield"); + + config.save(); + + StoredConfig cfg = new FileBasedConfig(file, FS.detect()); + cfg.load(); + assertEquals("一\t二\n三", cfg.getString("USER", "ming", "password")); + assertEquals("白老鼠", cfg.getString("USER", "ming", "displayName")); + assertEquals("Mickey \"白老鼠\" Whitfield", cfg.getString("USER", "ming", "peepo")); + } + } |