<classpathentry kind="lib" path="ext/force-wsc-24.0.0.jar" sourcepath="ext/src/force-wsc-24.0.0.jar" />
<classpathentry kind="lib" path="ext/js-1.7R2.jar" sourcepath="ext/src/js-1.7R2.jar" />
<classpathentry kind="lib" path="ext/freemarker-2.3.19.jar" sourcepath="ext/src/freemarker-2.3.19.jar" />
+ <classpathentry kind="lib" path="ext/waffle-jna-1.5.jar" sourcepath="ext/src/waffle-jna-1.5.jar" />
+ <classpathentry kind="lib" path="ext/platform-3.5.0.jar" sourcepath="ext/src/platform-3.5.0.jar" />
+ <classpathentry kind="lib" path="ext/jna-3.5.0.jar" sourcepath="ext/src/jna-3.5.0.jar" />
+ <classpathentry kind="lib" path="ext/guava-13.0.1.jar" sourcepath="ext/src/guava-13.0.1.jar" />
<classpathentry kind="lib" path="ext/junit-4.11.jar" sourcepath="ext/src/junit-4.11.jar" />
<classpathentry kind="lib" path="ext/hamcrest-core-1.3.jar" sourcepath="ext/src/hamcrest-core-1.3.jar" />
<classpathentry kind="lib" path="ext/selenium-java-2.28.0.jar" sourcepath="ext/src/selenium-java-2.28.0.jar" />
<classpathentry kind="lib" path="ext/cglib-nodep-2.1_3.jar" sourcepath="ext/src/cglib-nodep-2.1_3.jar" />
<classpathentry kind="lib" path="ext/json-20080701.jar" sourcepath="ext/src/json-20080701.jar" />
<classpathentry kind="lib" path="ext/selenium-api-2.28.0.jar" sourcepath="ext/src/selenium-api-2.28.0.jar" />
- <classpathentry kind="lib" path="ext/guava-13.0.1.jar" sourcepath="ext/src/guava-13.0.1.jar" />
<classpathentry kind="lib" path="ext/httpclient-4.2.1.jar" sourcepath="ext/src/httpclient-4.2.1.jar" />
<classpathentry kind="lib" path="ext/httpcore-4.2.1.jar" sourcepath="ext/src/httpcore-4.2.1.jar" />
<classpathentry kind="lib" path="ext/commons-logging-1.1.1.jar" sourcepath="ext/src/commons-logging-1.1.1.jar" />
<classpathentry kind="lib" path="ext/commons-codec-1.6.jar" sourcepath="ext/src/commons-codec-1.6.jar" />
<classpathentry kind="lib" path="ext/commons-exec-1.1.jar" sourcepath="ext/src/commons-exec-1.1.jar" />
- <classpathentry kind="lib" path="ext/jna-3.4.0.jar" sourcepath="ext/src/jna-3.4.0.jar" />
- <classpathentry kind="lib" path="ext/platform-3.4.0.jar" sourcepath="ext/src/platform-3.4.0.jar" />
<classpathentry kind="lib" path="ext/commons-io-2.2.jar" sourcepath="ext/src/commons-io-2.2.jar" />
<classpathentry kind="output" path="bin/classes" />
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER" />
FreeMarker, release under a\r
modified BSD License. (http://www.freemarker.org/docs/app_license.html)\r
\r
- http://www.freemarker.org/
\ No newline at end of file
+ http://www.freemarker.org/\r
+\r
+---------------------------------------------------------------------------\r
+Waffle\r
+---------------------------------------------------------------------------\r
+ Waffle, release under the\r
+ Eclipse Public License, version 1.0\r
+ \r
+ http://dblock.github.io/waffle\r
+\r
+---------------------------------------------------------------------------\r
+JNA\r
+---------------------------------------------------------------------------\r
+ JNA, release under the\r
+ Lesser GNU Public License, version 2.1\r
+ \r
+ https://github.com/twall/jna\r
+ \r
+---------------------------------------------------------------------------\r
+Guava\r
+---------------------------------------------------------------------------\r
+ Guava, release under the\r
+ Apache License 2.0.\r
+ \r
+ https://code.google.com/p/guava-libraries\r
+
\ No newline at end of file
- compile 'org.apache.commons:commons-compress:1.4.1' :war
- compile 'com.force.api:force-partner-api:24.0.0' :war
- compile 'org.freemarker:freemarker:2.3.19' :war
+- compile 'com.github.dblock.waffle:waffle-jna:1.5' :war
- test 'junit'
# Dependencies for Selenium web page testing
- test 'org.seleniumhq.selenium:selenium-java:${selenium.version}' @jar
<class name="com.gitblit.LdapUserService" />\r
<class name="com.gitblit.RedmineUserService" />\r
<class name="com.gitblit.SalesforceUserService" />\r
+ <class name="com.gitblit.WindowsUserService" />\r
</mx:genjar>\r
\r
<!-- Build the WAR file -->\r
<class name="com.gitblit.LdapUserService" />\r
<class name="com.gitblit.RedmineUserService" />\r
<class name="com.gitblit.SalesforceUserService" />\r
+ <class name="com.gitblit.WindowsUserService" />\r
</mx:genjar>\r
\r
<!-- Build Express Zip file -->\r
</SOURCES>
</library>
</orderEntry>
+ <orderEntry type="module-library">
+ <library name="waffle-jna-1.5.jar">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/ext/waffle-jna-1.5.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/ext/src/waffle-jna-1.5.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library name="platform-3.5.0.jar">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/ext/platform-3.5.0.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/ext/src/platform-3.5.0.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library name="jna-3.5.0.jar">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/ext/jna-3.5.0.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/ext/src/jna-3.5.0.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library name="guava-13.0.1.jar">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/ext/guava-13.0.1.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/ext/src/guava-13.0.1.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
<orderEntry type="module-library" scope="TEST">
<library name="junit-4.11.jar">
<CLASSES>
</SOURCES>
</library>
</orderEntry>
- <orderEntry type="module-library" scope="TEST">
- <library name="guava-13.0.1.jar">
- <CLASSES>
- <root url="jar://$MODULE_DIR$/ext/guava-13.0.1.jar!/" />
- </CLASSES>
- <JAVADOC />
- <SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/guava-13.0.1.jar!/" />
- </SOURCES>
- </library>
- </orderEntry>
<orderEntry type="module-library" scope="TEST">
<library name="httpclient-4.2.1.jar">
<CLASSES>
</SOURCES>
</library>
</orderEntry>
- <orderEntry type="module-library" scope="TEST">
- <library name="jna-3.4.0.jar">
- <CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jna-3.4.0.jar!/" />
- </CLASSES>
- <JAVADOC />
- <SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jna-3.4.0.jar!/" />
- </SOURCES>
- </library>
- </orderEntry>
- <orderEntry type="module-library" scope="TEST">
- <library name="platform-3.4.0.jar">
- <CLASSES>
- <root url="jar://$MODULE_DIR$/ext/platform-3.4.0.jar!/" />
- </CLASSES>
- <JAVADOC />
- <SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/platform-3.4.0.jar!/" />
- </SOURCES>
- </library>
- </orderEntry>
<orderEntry type="module-library" scope="TEST">
<library name="commons-io-2.2.jar">
<CLASSES>
- Updated Polish translation\r
- Updated Japanese translation\r
\r
- additions: \r
+ additions:\r
+ - Added WindowsUserService to authenticate users against Windows accounts (issue-250)\r
- Global and per-repository setting to exclude authors from metrics (issue-251)\r
- Added SalesForce.com user service\r
- Added simple star/unstar function to flag or bookmark interesting repositories\r
- Bandarupalli Satyanarayana\r
- Chad Horohoe\r
- Christian Aistleitner\r
+ - Colin Bowern\r
- David Ostrovsky\r
- Egbert Teeselink\r
- Hige Maniya\r
- Iconic font\r
- AngularJS 1.0.7\r
- FreeMarker 2.3.19\r
+ - Waffle 1.5\r
+ - JNA 3.5.0\r
+ - Guava 13.0.1\r
\r
settings:\r
- { name: 'git.daemonBindInterface', defaultValue: 'localhost' }\r
- { name: 'git.daemonPort', defaultValue: 0 }\r
- - { name: 'git.defaultIncrementalPushTagPrefix', defaultValue: 'r' }\r
+ - { name: 'git.defaultIncrementalPushTagPrefix', defaultValue: 'r' }\r
- { name: 'mail.smtps', defaultValue: 'false' }\r
- { name: 'realm.container.autoCreateAccounts', defaultValue: 'false' }\r
- { name: 'realm.salesforce.backingUserService', defaultValue: 'users.conf' }\r
- { name: 'realm.salesforce.orgId', defaultValue: 0 }\r
+ - { name: 'realm.windows.defaultDomain', defaultValue: ' ' }\r
+ - { name: 'realm.windows.backingUserService', defaultValue: 'users.conf' }\r
- { name: 'web.activityDurationChoices', defaultValue: '7 14 28 60 90 180' }\r
- { name: 'web.allowAppCloneLinks', defaultValue: 'true' }\r
- { name: 'web.forceDefaultLocale', defaultValue: ' ' }\r
# com.gitblit.LdapUserService\r
# com.gitblit.RedmineUserService\r
# com.gitblit.SalesforceUserService\r
+# com.gitblit.WindowsUserService\r
#\r
# Any custom user service implementation must have a public default constructor.\r
#\r
# SINCE 1.3.0\r
realm.container.autoCreateAccounts = false\r
\r
+# The WindowsUserService must be backed by another user service for standard user\r
+# and team management.\r
+# default: users.conf\r
+#\r
+# RESTART REQUIRED\r
+# BASEFOLDER\r
+# SINCE 1.3.0\r
+realm.windows.backingUserService = ${baseFolder}/users.conf\r
+\r
+# Allow or prohibit Windows guest account logins\r
+#\r
+# SINCE 1.3.0\r
+realm.windows.allowGuests = false\r
+\r
+# The default domain for authentication.\r
+#\r
+# If specified, this domain will be used for authentication UNLESS the supplied\r
+# login name manually specifies a domain (.e.g. mydomain\james or james@mydomain)\r
+#\r
+# If unspecified, the username must be specified in UPN format (name@domain).\r
+#\r
+# if "." (dot) is specified, ONLY the local account database will be used.\r
+#\r
+# SINCE 1.3.0\r
+realm.windows.defaultDomain =\r
+\r
# The SalesforceUserService must be backed by another user service for standard user\r
# and team management.\r
# default: users.conf\r
#\r
# RESTART REQUIRED\r
# BASEFOLDER\r
+# SINCE 1.3.0\r
realm.salesforce.backingUserService = ${baseFolder}/users.conf\r
\r
# Restrict the Salesforce user to members of this org.\r
}\r
\r
public static enum AccountType {\r
- LOCAL, LDAP, REDMINE, SALESFORCE;\r
+ LOCAL, LDAP, REDMINE, SALESFORCE, WINDOWS;\r
\r
public boolean isLocal() {\r
return this == LOCAL;\r
--- /dev/null
+/*\r
+ * Copyright 2013 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit;\r
+\r
+import java.io.File;\r
+import java.util.Set;\r
+import java.util.TreeSet;\r
+\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import waffle.windows.auth.IWindowsAccount;\r
+import waffle.windows.auth.IWindowsAuthProvider;\r
+import waffle.windows.auth.IWindowsComputer;\r
+import waffle.windows.auth.IWindowsIdentity;\r
+import waffle.windows.auth.impl.WindowsAuthProviderImpl;\r
+\r
+import com.gitblit.Constants.AccountType;\r
+import com.gitblit.models.UserModel;\r
+import com.gitblit.utils.ArrayUtils;\r
+import com.gitblit.utils.StringUtils;\r
+import com.sun.jna.platform.win32.Win32Exception;\r
+\r
+/**\r
+ * Implementation of a Windows user service.\r
+ * \r
+ * @author James Moger\r
+ */\r
+public class WindowsUserService extends GitblitUserService {\r
+\r
+ private final Logger logger = LoggerFactory.getLogger(WindowsUserService.class);\r
+\r
+ private IStoredSettings settings;\r
+ \r
+ private IWindowsAuthProvider waffle;\r
+\r
+ public WindowsUserService() {\r
+ super();\r
+ }\r
+\r
+ @Override\r
+ public void setup(IStoredSettings settings) {\r
+ this.settings = settings;\r
+\r
+ String file = settings.getString(Keys.realm.windows.backingUserService, "${baseFolder}/users.conf");\r
+ File realmFile = GitBlit.getFileOrFolder(file);\r
+\r
+ serviceImpl = createUserService(realmFile);\r
+ logger.info("Windows User Service backed by " + serviceImpl.toString());\r
+ \r
+ waffle = new WindowsAuthProviderImpl();\r
+ IWindowsComputer computer = waffle.getCurrentComputer();\r
+ logger.info(" name = " + computer.getComputerName());\r
+ logger.info(" status = " + describeJoinStatus(computer.getJoinStatus()));\r
+ logger.info(" memberOf = " + computer.getMemberOf());\r
+ //logger.info(" groups = " + Arrays.asList(computer.getGroups()));\r
+ }\r
+ \r
+ protected String describeJoinStatus(String value) {\r
+ if ("NetSetupUnknownStatus".equals(value)) {\r
+ return "unknown";\r
+ } else if ("NetSetupUnjoined".equals(value)) {\r
+ return "not joined";\r
+ } else if ("NetSetupWorkgroupName".equals(value)) {\r
+ return "joined to a workgroup";\r
+ } else if ("NetSetupDomainName".equals(value)) {\r
+ return "joined to a domain";\r
+ }\r
+ return value;\r
+ }\r
+\r
+ @Override\r
+ public boolean supportsCredentialChanges() {\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public boolean supportsDisplayNameChanges() {\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public boolean supportsEmailAddressChanges() {\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public boolean supportsTeamMembershipChanges() {\r
+ return true;\r
+ }\r
+ \r
+ @Override\r
+ protected AccountType getAccountType() {\r
+ return AccountType.WINDOWS;\r
+ }\r
+\r
+ @Override\r
+ public UserModel authenticate(String username, char[] password) {\r
+ if (isLocalAccount(username)) {\r
+ // local account, bypass Windows authentication\r
+ return super.authenticate(username, password);\r
+ }\r
+\r
+ String defaultDomain = settings.getString(Keys.realm.windows.defaultDomain, null);\r
+ if (StringUtils.isEmpty(defaultDomain)) {\r
+ // ensure that default domain is null\r
+ defaultDomain = null;\r
+ }\r
+\r
+ if (defaultDomain != null) {\r
+ // sanitize username\r
+ if (username.startsWith(defaultDomain + "\\")) {\r
+ // strip default domain from domain\ username\r
+ username = username.substring(defaultDomain.length() + 1);\r
+ } else if (username.endsWith("@" + defaultDomain)) {\r
+ // strip default domain from username@domain\r
+ username = username.substring(0, username.lastIndexOf('@'));\r
+ }\r
+ }\r
+\r
+ IWindowsIdentity identity = null;\r
+ try {\r
+ if (username.indexOf('@') > -1 || username.indexOf('\\') > -1) {\r
+ // manually specified domain\r
+ identity = waffle.logonUser(username, new String(password));\r
+ } else {\r
+ // no domain specified, use default domain\r
+ identity = waffle.logonDomainUser(username, defaultDomain, new String(password));\r
+ }\r
+ } catch (Win32Exception e) {\r
+ logger.error(e.getMessage());\r
+ return null;\r
+ }\r
+\r
+ if (identity.isGuest() && !settings.getBoolean(Keys.realm.windows.allowGuests, false)) {\r
+ logger.warn("Guest account access is disabled");\r
+ identity.dispose();\r
+ return null;\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 Windows identity\r
+ user.accountType = getAccountType();\r
+ String fqn = identity.getFqn();\r
+ if (fqn.indexOf('\\') > -1) {\r
+ user.displayName = fqn.substring(fqn.lastIndexOf('\\') + 1);\r
+ } else {\r
+ user.displayName = fqn;\r
+ }\r
+ user.password = Constants.EXTERNAL_ACCOUNT;\r
+\r
+ Set<String> groupNames = new TreeSet<String>();\r
+ for (IWindowsAccount group : identity.getGroups()) {\r
+ groupNames.add(group.getFqn());\r
+ }\r
+ \r
+ if (groupNames.contains("BUILTIN\\Administrators")) {\r
+ // local administrator\r
+ user.canAdmin = true;\r
+ }\r
+ \r
+ // TODO consider mapping Windows groups to teams\r
+\r
+ // push the changes to the backing user service\r
+ super.updateUserModel(user);\r
+\r
+\r
+ // cleanup resources\r
+ identity.dispose();\r
+ \r
+ return user;\r
+ }\r
+}\r
- [Commons-Compress](http://commons.apache.org/compress) (Apache 2.0)\r
- [XZ for Java](http://tukaani.org/xz/java.html) (Public Domain)\r
- [FreeMarker](http://www.freemarker.org) (modified BSD)\r
+- [Waffle](http://dblock.github.io/waffle) (EPL 1.0)\r
+- [JNA](https://github.com/twall/jna) (LGPL 2.1)\r
+- [Guava](https://code.google.com/p/guava-libraries) (Apache 2.0)\r
\r
### Other Build Dependencies\r
- [Fancybox image viewer](http://fancybox.net) (MIT and GPL dual-licensed)\r
- LDAP authentication and optional LDAP-controlled Team memberships\r
- Redmine authentication\r
- Salesforce.com authentication\r
+- Windows authentication\r
- Gravatar integration\r
- Git-notes display support\r
- Submodule support\r