<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/libpam4j-1.7.jar" sourcepath="ext/src/libpam4j-1.7.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" />
- 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
+- compile 'org.kohsuke:libpam4j:1.7' :war
- test 'junit'
# Dependencies for Selenium web page testing
- test 'org.seleniumhq.selenium:selenium-java:${selenium.version}' @jar
<class name="com.gitblit.RedmineUserService" />\r
<class name="com.gitblit.SalesforceUserService" />\r
<class name="com.gitblit.WindowsUserService" />\r
+ <class name="com.gitblit.PAMUserService" />\r
</mx:genjar>\r
\r
<!-- Build the WAR file -->\r
<class name="com.gitblit.RedmineUserService" />\r
<class name="com.gitblit.SalesforceUserService" />\r
<class name="com.gitblit.WindowsUserService" />\r
+ <class name="com.gitblit.PAMUserService" />\r
</mx:genjar>\r
\r
<!-- Build Express Zip file -->\r
</SOURCES>
</library>
</orderEntry>
+ <orderEntry type="module-library">
+ <library name="libpam4j-1.7.jar">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/ext/libpam4j-1.7.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/ext/src/libpam4j-1.7.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
<orderEntry type="module-library" scope="TEST">
<library name="junit-4.11.jar">
<CLASSES>
additions:
- Added optional browser-side page caching using Last-Modified and Cache-Control for the dashboard, activity, project, and several repository pages
- Added a GET_USER request type for the RPC mechanism (issue-275)
+ - Added PAMUserService to authenticate against a local Linux/Unix/MacOSX server
dependencyChanges: ~
settings:
- { name: 'web.pageCacheExpires', defaultValue: 0 }
+ - { name: 'realm.pam.backingUserService', defaultValue: 'users.conf' }
+ - { name: 'realm.pam.serviceName', defaultValue: 'system-auth' }
contributors:
- Rainer Alföldi
- Liyu Wang
# com.gitblit.RedmineUserService\r
# com.gitblit.SalesforceUserService\r
# com.gitblit.WindowsUserService\r
+# com.gitblit.PAMUserService\r
#\r
# Any custom user service implementation must have a public default constructor.\r
#\r
# SINCE 1.3.0\r
realm.windows.defaultDomain =\r
\r
+# The PAMUserService 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.1\r
+realm.pam.backingUserService = ${baseFolder}/users.conf\r
+\r
+# The PAM service name for authentication.\r
+# default: system-auth\r
+#\r
+# SINCE 1.3.1\r
+realm.pam.serviceName = system-auth\r
+\r
# The SalesforceUserService must be backed by another user service for standard user\r
# and team management.\r
# default: users.conf\r
}\r
\r
public static enum AccountType {\r
- LOCAL, EXTERNAL, LDAP, REDMINE, SALESFORCE, WINDOWS;\r
+ LOCAL, EXTERNAL, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM;\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
+\r
+import org.jvnet.libpam.PAM;\r
+import org.jvnet.libpam.PAMException;\r
+import org.jvnet.libpam.impl.CLibrary;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\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
+\r
+/**\r
+ * Implementation of a PAM user service for Linux/Unix/MacOSX.\r
+ * \r
+ * @author James Moger\r
+ */\r
+public class PAMUserService extends GitblitUserService {\r
+\r
+ private final Logger logger = LoggerFactory.getLogger(PAMUserService.class);\r
+\r
+ private IStoredSettings settings;\r
+ \r
+ public PAMUserService() {\r
+ super();\r
+ }\r
+\r
+ @Override\r
+ public void setup(IStoredSettings settings) {\r
+ this.settings = settings;\r
+\r
+ String file = settings.getString(Keys.realm.pam.backingUserService, "${baseFolder}/users.conf");\r
+ File realmFile = GitBlit.getFileOrFolder(file);\r
+\r
+ serviceImpl = createUserService(realmFile);\r
+ logger.info("PAM User Service backed by " + serviceImpl.toString());\r
+ \r
+ // Try to identify the passwd database\r
+ String [] files = { "/etc/shadow", "/etc/master.passwd" };\r
+ File passwdFile = null;\r
+ for (String name : files) {\r
+ File f = new File(name);\r
+ if (f.exists()) {\r
+ passwdFile = f;\r
+ break;\r
+ }\r
+ }\r
+ if (passwdFile == null) {\r
+ logger.error("PAM User Service could not find a passwd database!");\r
+ } else if (!passwdFile.canRead()) {\r
+ logger.error("PAM User Service can not read passwd database {}! PAM authentications may fail!", passwdFile);\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public boolean supportsCredentialChanges() {\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public boolean supportsDisplayNameChanges() {\r
+ return true;\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.PAM;\r
+ }\r
+\r
+ @Override\r
+ public UserModel authenticate(String username, char[] password) {\r
+ if (isLocalAccount(username)) {\r
+ // local account, bypass PAM authentication\r
+ return super.authenticate(username, password);\r
+ }\r
+ \r
+ if (CLibrary.libc.getpwnam(username) == null) {\r
+ logger.warn("Can not get PAM passwd for " + username);\r
+ return null;\r
+ }\r
+\r
+ PAM pam = null;\r
+ try {\r
+ String serviceName = settings.getString(Keys.realm.pam.serviceName, "system-auth");\r
+ pam = new PAM(serviceName);\r
+ pam.authenticate(username, new String(password));\r
+ } catch (PAMException e) {\r
+ logger.error(e.getMessage());\r
+ return null;\r
+ } finally {\r
+ pam.dispose();\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 UnixUser\r
+ user.accountType = getAccountType();\r
+ user.password = Constants.EXTERNAL_ACCOUNT;\r
+\r
+ // TODO consider mapping PAM groups to teams\r
+\r
+ // push the changes to the backing user service\r
+ super.updateUserModel(user);\r
+ \r
+ return user;\r
+ }\r
+}\r
- Redmine authentication\r
- Salesforce.com authentication\r
- Windows authentication\r
+- PAM authentication\r
- Gravatar integration\r
- Git-notes display support\r
- Submodule support\r
\r
* LDAP authentication\r
* Windows authentication\r
+* PAM authentication\r
* Redmine auhentication\r
* Salesforce.com authentication\r
* Servlet container authentication\r
realm.userService = com.gitblit.WindowsUserService\r
realm.windows.defaultDomain =\r
\r
+### PAM Authentication\r
+\r
+PAM authentication is based on the use of libpam4j and JNA. To use this service, your Gitblit server must be installed on a Linux/Unix/MacOSX machine and the user that Gitblit runs-as must have root permissions.\r
+\r
+ realm.userService = com.gitblit.PAMUserService\r
+ realm.pam.serviceName = system-auth\r
+\r
### Redmine Authentication\r
\r
You may authenticate your users against a Redmine installation as long as your Redmine install has properly enabled [API authentication](http://www.redmine.org/projects/redmine/wiki/Rest_Api#Authentication). This user service only supports user authentication; it does not support team creation based on Redmine groups. Redmine administrators will also be Gitblit administrators.\r
- Groovy push hook scripts\r
- Pluggable user service mechanism\r
- LDAP authentication with optional LDAP-controlled Team memberships\r
- - Redmine authentication\r
- - SalesForce.com authentication\r
- - Windows authentication\r
+ - Redmine authentication\r
+ - SalesForce.com authentication\r
+ - Windows authentication\r
+ - PAM authentication\r
- Custom authentication, authorization, and user management\r
- Rich RSS feeds\r
- JSON-based RPC mechanism\r