]> source.dussan.org Git - gitblit.git/commitdiff
Allow username/password Redmine authentication
authorJames Moger <james.moger@gitblit.com>
Sun, 6 Jan 2013 22:22:43 +0000 (17:22 -0500)
committerJames Moger <james.moger@gitblit.com>
Sun, 6 Jan 2013 22:22:43 +0000 (17:22 -0500)
src/com/gitblit/RedmineUserService.java
tests/com/gitblit/tests/RedmineUserServiceTest.java

index 2fa14b73e7ddc1bf78b80c24066488bc625ffedb..504593fba61a170667e9b2fc2678ef1cf35d179d 100644 (file)
@@ -86,69 +86,92 @@ public class RedmineUserService extends GitblitUserService {
                        return super.authenticate(username, password);\r
                }\r
 \r
-        String urlText = this.settings.getString(Keys.realm.redmine.url, "");\r
-        if (!urlText.endsWith("/")) {\r
-            urlText.concat("/");\r
+        String jsonString = null;\r
+        try {\r
+               // first attempt by username/password\r
+               jsonString = getCurrentUserAsJson(username, password);\r
+        } catch (Exception e1) {\r
+               logger.warn("Failed to authenticate via username/password against Redmine");\r
+               try {\r
+                       // second attempt is by apikey\r
+                       jsonString = getCurrentUserAsJson(null, password);\r
+                       username = null;\r
+               } catch (Exception e2) {\r
+                       logger.error("Failed to authenticate via apikey against Redmine", e2);\r
+                       return null;\r
+               }\r
         }\r
-        String apiKey = String.valueOf(password);\r
-\r
+        \r
+        RedmineCurrent current = null;\r
         try {\r
-            String jsonString = getCurrentUserAsJson(urlText, apiKey);\r
-\r
-            RedmineCurrent current = new Gson().fromJson(jsonString, RedmineCurrent.class);\r
-            String login = current.user.login;\r
-\r
-            boolean canAdmin = true;\r
-            if (StringUtils.isEmpty(login)) {\r
-                login = current.user.mail;\r
-                \r
-               // non admin user can not get login name\r
-               // TODO review this assumption, if it is true, it is undocumented\r
-                canAdmin = false;\r
-            }\r
-            \r
-            UserModel user = getUserModel(login);\r
-            if (user == null)  // create user object for new authenticated user\r
-               user = new UserModel(login);\r
-            \r
-            // create a user cookie\r
-                       if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {\r
-                               user.cookie = StringUtils.getSHA1(user.username + new String(password));\r
-                       }\r
-            \r
-            // update user attributes from Redmine\r
-                       user.accountType = getAccountType();\r
-                       user.canAdmin = canAdmin;\r
-               user.displayName = current.user.firstname + " " + current.user.lastname;\r
-               user.emailAddress = current.user.mail;\r
-               user.password = ExternalAccount;\r
-               \r
-               // TODO Redmine group mapping for administration & teams\r
-               // http://www.redmine.org/projects/redmine/wiki/Rest_Users\r
-               \r
-               // push the changes to the backing user service\r
-               super.updateUserModel(user);\r
-               \r
-            return user;\r
-        } catch (IOException e) {\r
-            logger.error("authenticate", e);\r
+               current = new Gson().fromJson(jsonString, RedmineCurrent.class);\r
+        } catch (Exception e) {\r
+               logger.error("Failed to deserialize Redmine json response: " + jsonString, e);\r
+               return null;\r
+        }\r
+\r
+        if (StringUtils.isEmpty(username)) {\r
+               // if the username has been reset because of apikey authentication\r
+               // then use the email address of the user. this is the original\r
+               // behavior as contributed by github/mallowlabs\r
+               username = current.user.mail;\r
+        }\r
+\r
+        UserModel user = getUserModel(username);\r
+        if (user == null)      // create user object for new authenticated user\r
+               user = new UserModel(username.toLowerCase());\r
+\r
+        // create a user cookie\r
+        if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {\r
+               user.cookie = StringUtils.getSHA1(user.username + new String(password));\r
+        }\r
+\r
+        // update user attributes from Redmine\r
+        user.accountType = getAccountType();\r
+        user.displayName = current.user.firstname + " " + current.user.lastname;\r
+        user.emailAddress = current.user.mail;\r
+        user.password = ExternalAccount;\r
+        if (!StringUtils.isEmpty(current.user.login)) {\r
+               // only admin users can get login name\r
+               // evidently this is an undocumented behavior of Redmine\r
+               user.canAdmin = true;\r
         }\r
-        return null;\r
+\r
+        // TODO consider Redmine group mapping for team membership\r
+        // http://www.redmine.org/projects/redmine/wiki/Rest_Users\r
+\r
+        // push the changes to the backing user service\r
+        super.updateUserModel(user);\r
+\r
+        return user;\r
     }\r
 \r
-    private String getCurrentUserAsJson(String url, String apiKey) throws IOException {\r
+    private String getCurrentUserAsJson(String username, char [] password) throws IOException {\r
         if (testingJson != null) { // for testing\r
             return testingJson;\r
         }\r
 \r
-        String apiUrl = url + "users/current.json?key=" + apiKey;\r
-        HttpURLConnection http = (HttpURLConnection) ConnectionUtils.openConnection(apiUrl, null, null);\r
+        String url = this.settings.getString(Keys.realm.redmine.url, "");\r
+        if (!url.endsWith("/")) {\r
+               url.concat("/");\r
+        }\r
+        HttpURLConnection http;\r
+        if (username == null) {\r
+               // apikey authentication\r
+               String apiKey = String.valueOf(password);\r
+               String apiUrl = url + "users/current.json?key=" + apiKey;\r
+               http = (HttpURLConnection) ConnectionUtils.openConnection(apiUrl, null, null);\r
+        } else {\r
+               // username/password BASIC authentication\r
+               String apiUrl = url + "users/current.json";\r
+               http = (HttpURLConnection) ConnectionUtils.openConnection(apiUrl, username, password);\r
+        }\r
         http.setRequestMethod("GET");\r
         http.connect();\r
         InputStreamReader reader = new InputStreamReader(http.getInputStream());\r
         return IOUtils.toString(reader);\r
     }\r
-\r
+    \r
     /**\r
      * set json response. do NOT invoke from production code.\r
      * @param json json\r
index 0e12542db11d38bab50c6c85bdce2e2df6637c9f..12fa73ff4a07887f3881915e53b853d0db9e37bf 100644 (file)
@@ -30,8 +30,8 @@ public class RedmineUserServiceTest {
         RedmineUserService redmineUserService = new RedmineUserService();\r
         redmineUserService.setup(new MemorySettings(new HashMap<String, Object>()));\r
         redmineUserService.setTestingCurrentUserAsJson(JSON);\r
-        UserModel userModel = redmineUserService.authenticate("RedmineUserId", "RedmineAPIKey".toCharArray());\r
-        assertThat(userModel.getName(), is("redmineuserid"));\r
+        UserModel userModel = redmineUserService.authenticate("RedmineAdminId", "RedmineAPIKey".toCharArray());\r
+        assertThat(userModel.getName(), is("redmineadminid"));\r
         assertThat(userModel.getDisplayName(), is("baz foo"));\r
         assertThat(userModel.emailAddress, is("baz@example.com"));\r
         assertNotNull(userModel.cookie);\r
@@ -44,7 +44,7 @@ public class RedmineUserServiceTest {
         redmineUserService.setup(new MemorySettings(new HashMap<String, Object>()));\r
         redmineUserService.setTestingCurrentUserAsJson(NOT_ADMIN_JSON);\r
         UserModel userModel = redmineUserService.authenticate("RedmineUserId", "RedmineAPIKey".toCharArray());\r
-        assertThat(userModel.getName(), is("baz@example.com"));\r
+        assertThat(userModel.getName(), is("redmineuserid"));\r
         assertThat(userModel.getDisplayName(), is("baz foo"));\r
         assertThat(userModel.emailAddress, is("baz@example.com"));\r
         assertNotNull(userModel.cookie);\r