James Moger
2015-11-22 ed552ba47c02779c270ffd62841d6d1048dade70
commit | author | age
04a985 1 /*
JM 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.auth;
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
24 import com.gitblit.Constants;
25 import com.gitblit.Constants.AccountType;
6e3481 26 import com.gitblit.Constants.Role;
04a985 27 import com.gitblit.Keys;
JM 28 import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
6e3481 29 import com.gitblit.models.TeamModel;
04a985 30 import com.gitblit.models.UserModel;
JM 31
32 /**
33  * Implementation of PAM authentication for Linux/Unix/MacOSX.
34  *
35  * @author James Moger
36  */
37 public class PAMAuthProvider extends UsernamePasswordAuthenticationProvider {
38
39     public PAMAuthProvider() {
40         super("pam");
41     }
42
43     @Override
44     public void setup() {
45         // Try to identify the passwd database
46         String [] files = { "/etc/shadow", "/etc/master.passwd" };
47         File passwdFile = null;
48         for (String name : files) {
49             File f = new File(name);
50             if (f.exists()) {
51                 passwdFile = f;
52                 break;
53             }
54         }
55         if (passwdFile == null) {
56             logger.error("PAM Authentication could not find a passwd database!");
57         } else if (!passwdFile.canRead()) {
58             logger.error("PAM Authentication can not read passwd database {}! PAM authentications may fail!", passwdFile);
59         }
60     }
61
62     @Override
63     public boolean supportsCredentialChanges() {
64         return false;
65     }
66
67     @Override
68     public boolean supportsDisplayNameChanges() {
69         return true;
70     }
71
72     @Override
73     public boolean supportsEmailAddressChanges() {
74         return true;
75     }
76
77     @Override
78     public boolean supportsTeamMembershipChanges() {
79         return true;
80     }
81
6e3481 82     @Override
JM 83     public boolean supportsRoleChanges(UserModel user, Role role) {
84         return true;
85     }
86
87     @Override
88     public boolean supportsRoleChanges(TeamModel team, Role role) {
89         return true;
90     }
91
04a985 92      @Override
JM 93     public AccountType getAccountType() {
94         return AccountType.PAM;
95     }
96
97     @Override
98     public UserModel authenticate(String username, char[] password) {
99         if (CLibrary.libc.getpwnam(username) == null) {
100             logger.warn("Can not get PAM passwd for " + username);
101             return null;
102         }
103
104         PAM pam = null;
105         try {
106             String serviceName = settings.getString(Keys.realm.pam.serviceName, "system-auth");
107             pam = new PAM(serviceName);
108             pam.authenticate(username, new String(password));
109         } catch (PAMException e) {
110             logger.error(e.getMessage());
111             return null;
112         } finally {
1fb542 113             if (pam != null) {
JM 114                 pam.dispose();
115             }
04a985 116         }
JM 117
118         UserModel user = userManager.getUserModel(username);
c1b0e4 119         if (user == null) {
JM 120             // create user object for new authenticated user
04a985 121             user = new UserModel(username.toLowerCase());
c1b0e4 122         }
04a985 123
JM 124         // create a user cookie
c1b0e4 125         setCookie(user, password);
04a985 126
JM 127         // update user attributes from UnixUser
128         user.accountType = getAccountType();
129         user.password = Constants.EXTERNAL_ACCOUNT;
130
131         // TODO consider mapping PAM groups to teams
132
133         // push the changes to the backing user service
134         updateUser(user);
135
136         return user;
137     }
138 }