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.util.Set;
19 import java.util.TreeSet;
20
21 import waffle.windows.auth.IWindowsAccount;
22 import waffle.windows.auth.IWindowsAuthProvider;
23 import waffle.windows.auth.IWindowsComputer;
24 import waffle.windows.auth.IWindowsIdentity;
25 import waffle.windows.auth.impl.WindowsAuthProviderImpl;
26
27 import com.gitblit.Constants;
28 import com.gitblit.Constants.AccountType;
6e3481 29 import com.gitblit.Constants.Role;
04a985 30 import com.gitblit.Keys;
JM 31 import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
6e3481 32 import com.gitblit.models.TeamModel;
04a985 33 import com.gitblit.models.UserModel;
JM 34 import com.gitblit.utils.StringUtils;
35 import com.sun.jna.platform.win32.Win32Exception;
36
37 /**
38  * Implementation of a Windows authentication provider.
39  *
40  * @author James Moger
41  */
42 public class WindowsAuthProvider extends UsernamePasswordAuthenticationProvider {
43
44     private IWindowsAuthProvider waffle;
45
46     public WindowsAuthProvider() {
47         super("windows");
48     }
49
50     @Override
51     public void setup() {
52
53         waffle = new WindowsAuthProviderImpl();
54         IWindowsComputer computer = waffle.getCurrentComputer();
55         logger.info("Windows Authentication Provider");
56         logger.info("      name = " + computer.getComputerName());
57         logger.info("    status = " + describeJoinStatus(computer.getJoinStatus()));
58         logger.info("  memberOf = " + computer.getMemberOf());
59         //logger.info("  groups     = " + Arrays.asList(computer.getGroups()));
60     }
61
62     protected String describeJoinStatus(String value) {
63         if ("NetSetupUnknownStatus".equals(value)) {
64             return "unknown";
65         } else if ("NetSetupUnjoined".equals(value)) {
66             return "not joined";
67         } else if ("NetSetupWorkgroupName".equals(value)) {
68             return "joined to a workgroup";
69         } else if ("NetSetupDomainName".equals(value)) {
70             return "joined to a domain";
71         }
72         return value;
73     }
74
75     @Override
76     public boolean supportsCredentialChanges() {
77         return false;
78     }
79
80     @Override
81     public boolean supportsDisplayNameChanges() {
82         return false;
83     }
84
85     @Override
86     public boolean supportsEmailAddressChanges() {
87         return true;
88     }
89
90     @Override
91     public boolean supportsTeamMembershipChanges() {
92         return true;
93     }
94
6e3481 95     @Override
JM 96     public boolean supportsRoleChanges(UserModel user, Role role) {
97         return true;
98     }
99
100     @Override
101     public boolean supportsRoleChanges(TeamModel team, Role role) {
102         return true;
103     }
104
04a985 105      @Override
JM 106     public AccountType getAccountType() {
107         return AccountType.WINDOWS;
108     }
109
110     @Override
111     public UserModel authenticate(String username, char[] password) {
112         String defaultDomain = settings.getString(Keys.realm.windows.defaultDomain, null);
113         if (StringUtils.isEmpty(defaultDomain)) {
114             // ensure that default domain is null
115             defaultDomain = null;
116         }
117
118         if (defaultDomain != null) {
119             // sanitize username
120             if (username.startsWith(defaultDomain + "\\")) {
121                 // strip default domain from domain\ username
122                 username = username.substring(defaultDomain.length() + 1);
123             } else if (username.endsWith("@" + defaultDomain)) {
124                 // strip default domain from username@domain
125                 username = username.substring(0, username.lastIndexOf('@'));
126             }
127         }
128
129         IWindowsIdentity identity = null;
130         try {
131             if (username.indexOf('@') > -1 || username.indexOf('\\') > -1) {
132                 // manually specified domain
133                 identity = waffle.logonUser(username, new String(password));
134             } else {
135                 // no domain specified, use default domain
136                 identity = waffle.logonDomainUser(username, defaultDomain, new String(password));
137             }
138         } catch (Win32Exception e) {
139             logger.error(e.getMessage());
140             return null;
141         }
142
143         if (identity.isGuest() && !settings.getBoolean(Keys.realm.windows.allowGuests, false)) {
144             logger.warn("Guest account access is disabled");
145             identity.dispose();
146             return null;
147         }
148
149         UserModel user = userManager.getUserModel(username);
c1b0e4 150         if (user == null) {
JM 151             // create user object for new authenticated user
04a985 152             user = new UserModel(username.toLowerCase());
c1b0e4 153         }
04a985 154
JM 155         // create a user cookie
c1b0e4 156         setCookie(user, password);
04a985 157
JM 158         // update user attributes from Windows identity
159         user.accountType = getAccountType();
160         String fqn = identity.getFqn();
161         if (fqn.indexOf('\\') > -1) {
162             user.displayName = fqn.substring(fqn.lastIndexOf('\\') + 1);
163         } else {
164             user.displayName = fqn;
165         }
166         user.password = Constants.EXTERNAL_ACCOUNT;
167
168         Set<String> groupNames = new TreeSet<String>();
169            for (IWindowsAccount group : identity.getGroups()) {
170                groupNames.add(group.getFqn());
171         }
172
fa38a1 173            if (settings.getBoolean(Keys.realm.windows.permitBuiltInAdministrators, true)) {
JM 174                if (groupNames.contains("BUILTIN\\Administrators")) {
175                    // local administrator
176                    user.canAdmin = true;
177                }
04a985 178         }
JM 179
180         // TODO consider mapping Windows groups to teams
181
182         // push the changes to the backing user service
183         updateUser(user);
184
185         // cleanup resources
186         identity.dispose();
187
188         return user;
189     }
190 }