Skip to content

Commit 2659e74

Browse files
committed
Added PAMUserService for local Linux/Unix/MacOSX account authentication
1 parent 52fc945 commit 2659e74

File tree

11 files changed

+190
-4
lines changed

11 files changed

+190
-4
lines changed

.classpath

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
<classpathentry kind="lib" path="ext/platform-3.5.0.jar" sourcepath="ext/src/platform-3.5.0.jar" />
4646
<classpathentry kind="lib" path="ext/jna-3.5.0.jar" sourcepath="ext/src/jna-3.5.0.jar" />
4747
<classpathentry kind="lib" path="ext/guava-13.0.1.jar" sourcepath="ext/src/guava-13.0.1.jar" />
48+
<classpathentry kind="lib" path="ext/libpam4j-1.7.jar" sourcepath="ext/src/libpam4j-1.7.jar" />
4849
<classpathentry kind="lib" path="ext/junit-4.11.jar" sourcepath="ext/src/junit-4.11.jar" />
4950
<classpathentry kind="lib" path="ext/hamcrest-core-1.3.jar" sourcepath="ext/src/hamcrest-core-1.3.jar" />
5051
<classpathentry kind="lib" path="ext/selenium-java-2.28.0.jar" sourcepath="ext/src/selenium-java-2.28.0.jar" />

build.moxie

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ dependencies:
150150
- compile 'com.force.api:force-partner-api:24.0.0' :war
151151
- compile 'org.freemarker:freemarker:2.3.19' :war
152152
- compile 'com.github.dblock.waffle:waffle-jna:1.5' :war
153+
- compile 'org.kohsuke:libpam4j:1.7' :war
153154
- test 'junit'
154155
# Dependencies for Selenium web page testing
155156
- test 'org.seleniumhq.selenium:selenium-java:${selenium.version}' @jar

build.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@
302302
<class name="com.gitblit.RedmineUserService" />
303303
<class name="com.gitblit.SalesforceUserService" />
304304
<class name="com.gitblit.WindowsUserService" />
305+
<class name="com.gitblit.PAMUserService" />
305306
</mx:genjar>
306307

307308
<!-- Build the WAR file -->
@@ -421,6 +422,7 @@
421422
<class name="com.gitblit.RedmineUserService" />
422423
<class name="com.gitblit.SalesforceUserService" />
423424
<class name="com.gitblit.WindowsUserService" />
425+
<class name="com.gitblit.PAMUserService" />
424426
</mx:genjar>
425427

426428
<!-- Build Express Zip file -->

gitblit.iml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,17 @@
468468
</SOURCES>
469469
</library>
470470
</orderEntry>
471+
<orderEntry type="module-library">
472+
<library name="libpam4j-1.7.jar">
473+
<CLASSES>
474+
<root url="jar://$MODULE_DIR$/ext/libpam4j-1.7.jar!/" />
475+
</CLASSES>
476+
<JAVADOC />
477+
<SOURCES>
478+
<root url="jar://$MODULE_DIR$/ext/src/libpam4j-1.7.jar!/" />
479+
</SOURCES>
480+
</library>
481+
</orderEntry>
471482
<orderEntry type="module-library" scope="TEST">
472483
<library name="junit-4.11.jar">
473484
<CLASSES>

releases.moxie

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@ r18: {
3232
additions:
3333
- Added optional browser-side page caching using Last-Modified and Cache-Control for the dashboard, activity, project, and several repository pages
3434
- Added a GET_USER request type for the RPC mechanism (issue-275)
35+
- Added PAMUserService to authenticate against a local Linux/Unix/MacOSX server
3536
dependencyChanges: ~
3637
settings:
3738
- { name: 'web.pageCacheExpires', defaultValue: 0 }
39+
- { name: 'realm.pam.backingUserService', defaultValue: 'users.conf' }
40+
- { name: 'realm.pam.serviceName', defaultValue: 'system-auth' }
3841
contributors:
3942
- Rainer Alföldi
4043
- Liyu Wang

src/main/distrib/data/gitblit.properties

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ web.projectsFile = ${baseFolder}/projects.conf
501501
# com.gitblit.RedmineUserService
502502
# com.gitblit.SalesforceUserService
503503
# com.gitblit.WindowsUserService
504+
# com.gitblit.PAMUserService
504505
#
505506
# Any custom user service implementation must have a public default constructor.
506507
#
@@ -1212,6 +1213,21 @@ realm.windows.allowGuests = false
12121213
# SINCE 1.3.0
12131214
realm.windows.defaultDomain =
12141215

1216+
# The PAMUserService must be backed by another user service for standard user
1217+
# and team management.
1218+
# default: users.conf
1219+
#
1220+
# RESTART REQUIRED
1221+
# BASEFOLDER
1222+
# SINCE 1.3.1
1223+
realm.pam.backingUserService = ${baseFolder}/users.conf
1224+
1225+
# The PAM service name for authentication.
1226+
# default: system-auth
1227+
#
1228+
# SINCE 1.3.1
1229+
realm.pam.serviceName = system-auth
1230+
12151231
# The SalesforceUserService must be backed by another user service for standard user
12161232
# and team management.
12171233
# default: users.conf

src/main/java/com/gitblit/Constants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ public boolean isStandard() {
480480
}
481481

482482
public static enum AccountType {
483-
LOCAL, EXTERNAL, LDAP, REDMINE, SALESFORCE, WINDOWS;
483+
LOCAL, EXTERNAL, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM;
484484

485485
public boolean isLocal() {
486486
return this == LOCAL;
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright 2013 gitblit.com.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.gitblit;
17+
18+
import java.io.File;
19+
20+
import org.jvnet.libpam.PAM;
21+
import org.jvnet.libpam.PAMException;
22+
import org.jvnet.libpam.impl.CLibrary;
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
26+
import com.gitblit.Constants.AccountType;
27+
import com.gitblit.models.UserModel;
28+
import com.gitblit.utils.ArrayUtils;
29+
import com.gitblit.utils.StringUtils;
30+
31+
/**
32+
* Implementation of a PAM user service for Linux/Unix/MacOSX.
33+
*
34+
* @author James Moger
35+
*/
36+
public class PAMUserService extends GitblitUserService {
37+
38+
private final Logger logger = LoggerFactory.getLogger(PAMUserService.class);
39+
40+
private IStoredSettings settings;
41+
42+
public PAMUserService() {
43+
super();
44+
}
45+
46+
@Override
47+
public void setup(IStoredSettings settings) {
48+
this.settings = settings;
49+
50+
String file = settings.getString(Keys.realm.pam.backingUserService, "${baseFolder}/users.conf");
51+
File realmFile = GitBlit.getFileOrFolder(file);
52+
53+
serviceImpl = createUserService(realmFile);
54+
logger.info("PAM User Service backed by " + serviceImpl.toString());
55+
56+
// Try to identify the passwd database
57+
String [] files = { "/etc/shadow", "/etc/master.passwd" };
58+
File passwdFile = null;
59+
for (String name : files) {
60+
File f = new File(name);
61+
if (f.exists()) {
62+
passwdFile = f;
63+
break;
64+
}
65+
}
66+
if (passwdFile == null) {
67+
logger.error("PAM User Service could not find a passwd database!");
68+
} else if (!passwdFile.canRead()) {
69+
logger.error("PAM User Service can not read passwd database {}! PAM authentications may fail!", passwdFile);
70+
}
71+
}
72+
73+
@Override
74+
public boolean supportsCredentialChanges() {
75+
return false;
76+
}
77+
78+
@Override
79+
public boolean supportsDisplayNameChanges() {
80+
return true;
81+
}
82+
83+
@Override
84+
public boolean supportsEmailAddressChanges() {
85+
return true;
86+
}
87+
88+
@Override
89+
public boolean supportsTeamMembershipChanges() {
90+
return true;
91+
}
92+
93+
@Override
94+
protected AccountType getAccountType() {
95+
return AccountType.PAM;
96+
}
97+
98+
@Override
99+
public UserModel authenticate(String username, char[] password) {
100+
if (isLocalAccount(username)) {
101+
// local account, bypass PAM authentication
102+
return super.authenticate(username, password);
103+
}
104+
105+
if (CLibrary.libc.getpwnam(username) == null) {
106+
logger.warn("Can not get PAM passwd for " + username);
107+
return null;
108+
}
109+
110+
PAM pam = null;
111+
try {
112+
String serviceName = settings.getString(Keys.realm.pam.serviceName, "system-auth");
113+
pam = new PAM(serviceName);
114+
pam.authenticate(username, new String(password));
115+
} catch (PAMException e) {
116+
logger.error(e.getMessage());
117+
return null;
118+
} finally {
119+
pam.dispose();
120+
}
121+
122+
UserModel user = getUserModel(username);
123+
if (user == null) // create user object for new authenticated user
124+
user = new UserModel(username.toLowerCase());
125+
126+
// create a user cookie
127+
if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
128+
user.cookie = StringUtils.getSHA1(user.username + new String(password));
129+
}
130+
131+
// update user attributes from UnixUser
132+
user.accountType = getAccountType();
133+
user.password = Constants.EXTERNAL_ACCOUNT;
134+
135+
// TODO consider mapping PAM groups to teams
136+
137+
// push the changes to the backing user service
138+
super.updateUserModel(user);
139+
140+
return user;
141+
}
142+
}

src/site/features.mkd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
- Redmine authentication
3838
- Salesforce.com authentication
3939
- Windows authentication
40+
- PAM authentication
4041
- Gravatar integration
4142
- Git-notes display support
4243
- Submodule support

src/site/setup_authentication.mkd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Gitblit supports additional authentication mechanisms aside from it's internal o
66

77
* LDAP authentication
88
* Windows authentication
9+
* PAM authentication
910
* Redmine auhentication
1011
* Salesforce.com authentication
1112
* Servlet container authentication
@@ -83,6 +84,13 @@ Windows authentication is based on the use of Waffle and JNA. It is known to wo
8384
realm.userService = com.gitblit.WindowsUserService
8485
realm.windows.defaultDomain =
8586

87+
### PAM Authentication
88+
89+
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.
90+
91+
realm.userService = com.gitblit.PAMUserService
92+
realm.pam.serviceName = system-auth
93+
8694
### Redmine Authentication
8795

8896
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.

0 commit comments

Comments
 (0)