diff options
-rw-r--r-- | .classpath | 1 | ||||
-rw-r--r-- | build.moxie | 1 | ||||
-rw-r--r-- | build.xml | 2 | ||||
-rw-r--r-- | gitblit.iml | 11 | ||||
-rw-r--r-- | releases.moxie | 3 | ||||
-rw-r--r-- | src/main/distrib/data/gitblit.properties | 16 | ||||
-rw-r--r-- | src/main/java/com/gitblit/Constants.java | 2 | ||||
-rw-r--r-- | src/main/java/com/gitblit/PAMUserService.java | 142 | ||||
-rw-r--r-- | src/site/features.mkd | 1 | ||||
-rw-r--r-- | src/site/setup_authentication.mkd | 8 | ||||
-rw-r--r-- | src/site/siteindex.mkd | 7 |
11 files changed, 190 insertions, 4 deletions
@@ -45,6 +45,7 @@ <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" /> diff --git a/build.moxie b/build.moxie index d15d916a..f417d3c6 100644 --- a/build.moxie +++ b/build.moxie @@ -150,6 +150,7 @@ dependencies: - 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 @@ -302,6 +302,7 @@ <class name="com.gitblit.RedmineUserService" />
<class name="com.gitblit.SalesforceUserService" />
<class name="com.gitblit.WindowsUserService" />
+ <class name="com.gitblit.PAMUserService" />
</mx:genjar>
<!-- Build the WAR file -->
@@ -421,6 +422,7 @@ <class name="com.gitblit.RedmineUserService" />
<class name="com.gitblit.SalesforceUserService" />
<class name="com.gitblit.WindowsUserService" />
+ <class name="com.gitblit.PAMUserService" />
</mx:genjar>
<!-- Build Express Zip file -->
diff --git a/gitblit.iml b/gitblit.iml index 85ba7791..c4ba270c 100644 --- a/gitblit.iml +++ b/gitblit.iml @@ -468,6 +468,17 @@ </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> diff --git a/releases.moxie b/releases.moxie index 17894a50..2f601eb5 100644 --- a/releases.moxie +++ b/releases.moxie @@ -32,9 +32,12 @@ r18: { 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 diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties index 1ee6d800..7f2f8b48 100644 --- a/src/main/distrib/data/gitblit.properties +++ b/src/main/distrib/data/gitblit.properties @@ -501,6 +501,7 @@ web.projectsFile = ${baseFolder}/projects.conf # com.gitblit.RedmineUserService
# com.gitblit.SalesforceUserService
# com.gitblit.WindowsUserService
+# com.gitblit.PAMUserService
#
# Any custom user service implementation must have a public default constructor.
#
@@ -1212,6 +1213,21 @@ realm.windows.allowGuests = false # SINCE 1.3.0
realm.windows.defaultDomain =
+# The PAMUserService must be backed by another user service for standard user
+# and team management.
+# default: users.conf
+#
+# RESTART REQUIRED
+# BASEFOLDER
+# SINCE 1.3.1
+realm.pam.backingUserService = ${baseFolder}/users.conf
+
+# The PAM service name for authentication.
+# default: system-auth
+#
+# SINCE 1.3.1
+realm.pam.serviceName = system-auth
+
# The SalesforceUserService must be backed by another user service for standard user
# and team management.
# default: users.conf
diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java index 67f9d65d..c180bafb 100644 --- a/src/main/java/com/gitblit/Constants.java +++ b/src/main/java/com/gitblit/Constants.java @@ -480,7 +480,7 @@ public class Constants { }
public static enum AccountType {
- LOCAL, EXTERNAL, LDAP, REDMINE, SALESFORCE, WINDOWS;
+ LOCAL, EXTERNAL, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM;
public boolean isLocal() {
return this == LOCAL;
diff --git a/src/main/java/com/gitblit/PAMUserService.java b/src/main/java/com/gitblit/PAMUserService.java new file mode 100644 index 00000000..692b0f4a --- /dev/null +++ b/src/main/java/com/gitblit/PAMUserService.java @@ -0,0 +1,142 @@ +/*
+ * Copyright 2013 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 org.jvnet.libpam.PAM;
+import org.jvnet.libpam.PAMException;
+import org.jvnet.libpam.impl.CLibrary;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.Constants.AccountType;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Implementation of a PAM user service for Linux/Unix/MacOSX.
+ *
+ * @author James Moger
+ */
+public class PAMUserService extends GitblitUserService {
+
+ private final Logger logger = LoggerFactory.getLogger(PAMUserService.class);
+
+ private IStoredSettings settings;
+
+ public PAMUserService() {
+ super();
+ }
+
+ @Override
+ public void setup(IStoredSettings settings) {
+ this.settings = settings;
+
+ String file = settings.getString(Keys.realm.pam.backingUserService, "${baseFolder}/users.conf");
+ File realmFile = GitBlit.getFileOrFolder(file);
+
+ serviceImpl = createUserService(realmFile);
+ logger.info("PAM User Service backed by " + serviceImpl.toString());
+
+ // Try to identify the passwd database
+ String [] files = { "/etc/shadow", "/etc/master.passwd" };
+ File passwdFile = null;
+ for (String name : files) {
+ File f = new File(name);
+ if (f.exists()) {
+ passwdFile = f;
+ break;
+ }
+ }
+ if (passwdFile == null) {
+ logger.error("PAM User Service could not find a passwd database!");
+ } else if (!passwdFile.canRead()) {
+ logger.error("PAM User Service can not read passwd database {}! PAM authentications may fail!", passwdFile);
+ }
+ }
+
+ @Override
+ public boolean supportsCredentialChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsDisplayNameChanges() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsEmailAddressChanges() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsTeamMembershipChanges() {
+ return true;
+ }
+
+ @Override
+ protected AccountType getAccountType() {
+ return AccountType.PAM;
+ }
+
+ @Override
+ public UserModel authenticate(String username, char[] password) {
+ if (isLocalAccount(username)) {
+ // local account, bypass PAM authentication
+ return super.authenticate(username, password);
+ }
+
+ if (CLibrary.libc.getpwnam(username) == null) {
+ logger.warn("Can not get PAM passwd for " + username);
+ return null;
+ }
+
+ PAM pam = null;
+ try {
+ String serviceName = settings.getString(Keys.realm.pam.serviceName, "system-auth");
+ pam = new PAM(serviceName);
+ pam.authenticate(username, new String(password));
+ } catch (PAMException e) {
+ logger.error(e.getMessage());
+ return null;
+ } finally {
+ pam.dispose();
+ }
+
+ UserModel user = getUserModel(username);
+ if (user == null) // create user object for new authenticated user
+ user = new UserModel(username.toLowerCase());
+
+ // create a user cookie
+ if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
+ user.cookie = StringUtils.getSHA1(user.username + new String(password));
+ }
+
+ // update user attributes from UnixUser
+ user.accountType = getAccountType();
+ user.password = Constants.EXTERNAL_ACCOUNT;
+
+ // TODO consider mapping PAM groups to teams
+
+ // push the changes to the backing user service
+ super.updateUserModel(user);
+
+ return user;
+ }
+}
diff --git a/src/site/features.mkd b/src/site/features.mkd index b9b44a52..d5bf4103 100644 --- a/src/site/features.mkd +++ b/src/site/features.mkd @@ -37,6 +37,7 @@ - Redmine authentication
- Salesforce.com authentication
- Windows authentication
+- PAM authentication
- Gravatar integration
- Git-notes display support
- Submodule support
diff --git a/src/site/setup_authentication.mkd b/src/site/setup_authentication.mkd index 7f606180..0ec07fa5 100644 --- a/src/site/setup_authentication.mkd +++ b/src/site/setup_authentication.mkd @@ -6,6 +6,7 @@ Gitblit supports additional authentication mechanisms aside from it's internal o * LDAP authentication
* Windows authentication
+* PAM authentication
* Redmine auhentication
* Salesforce.com authentication
* Servlet container authentication
@@ -83,6 +84,13 @@ Windows authentication is based on the use of Waffle and JNA. It is known to wo realm.userService = com.gitblit.WindowsUserService
realm.windows.defaultDomain =
+### PAM Authentication
+
+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.
+
+ realm.userService = com.gitblit.PAMUserService
+ realm.pam.serviceName = system-auth
+
### Redmine Authentication
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.
diff --git a/src/site/siteindex.mkd b/src/site/siteindex.mkd index f72e9c17..1b6dcdf4 100644 --- a/src/site/siteindex.mkd +++ b/src/site/siteindex.mkd @@ -68,9 +68,10 @@ Administrators can create and manage all repositories, user accounts, and teams - Groovy push hook scripts
- Pluggable user service mechanism
- LDAP authentication with optional LDAP-controlled Team memberships
- - Redmine authentication
- - SalesForce.com authentication
- - Windows authentication
+ - Redmine authentication
+ - SalesForce.com authentication
+ - Windows authentication
+ - PAM authentication
- Custom authentication, authorization, and user management
- Rich RSS feeds
- JSON-based RPC mechanism
|