1 /* 2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.security.auth.module; 27 28 import java.util.*; 29 import java.io.IOException; 30 import javax.security.auth.*; 31 import javax.security.auth.callback.*; 32 import javax.security.auth.login.*; 33 import javax.security.auth.spi.*; 34 import com.sun.security.auth.SolarisPrincipal; 35 import com.sun.security.auth.SolarisNumericUserPrincipal; 36 import com.sun.security.auth.SolarisNumericGroupPrincipal; 37 38 /** 39 * This {@code LoginModule} imports a user's Solaris 40 * {@code Principal} information ({@code SolarisPrincipal}, 41 * {@code SolarisNumericUserPrincipal}, 42 * and {@code SolarisNumericGroupPrincipal}) 43 * and associates them with the current {@code Subject}. 44 * 45 * <p> This LoginModule recognizes the debug option. 46 * If set to true in the login Configuration, 47 * debug messages will be output to the output stream, System.out. 48 * @deprecated As of JDK1.4, replaced by 49 * {@code com.sun.security.auth.module.UnixLoginModule}. 50 * This LoginModule is entirely deprecated and 51 * is here to allow for a smooth transition to the new 52 * UnixLoginModule. 53 * This class is subject to removal in a future version of Java SE. 54 * 55 */ 56 @Deprecated(since="1.4", forRemoval=true) 57 public class SolarisLoginModule implements LoginModule { 58 59 // initial state 60 private Subject subject; 61 private CallbackHandler callbackHandler; 62 private Map<String, ?> sharedState; 63 private Map<String, ?> options; 64 65 // configurable option 66 private boolean debug = true; 67 68 // SolarisSystem to retrieve underlying system info 69 @SuppressWarnings("removal") 70 private SolarisSystem ss; 71 72 // the authentication status 73 private boolean succeeded = false; 74 private boolean commitSucceeded = false; 75 76 // Underlying system info 77 @SuppressWarnings("removal") 78 private SolarisPrincipal userPrincipal; 79 @SuppressWarnings("removal") 80 private SolarisNumericUserPrincipal UIDPrincipal; 81 @SuppressWarnings("removal") 82 private SolarisNumericGroupPrincipal GIDPrincipal; 83 @SuppressWarnings("removal") 84 private LinkedList<SolarisNumericGroupPrincipal> supplementaryGroups = 85 new LinkedList<>(); 86 87 /** 88 * Initialize this {@code LoginModule}. 89 * 90 * @param subject the {@code Subject} to be authenticated. 91 * 92 * @param callbackHandler a {@code CallbackHandler} for communicating 93 * with the end user (prompting for usernames and 94 * passwords, for example). 95 * 96 * @param sharedState shared {@code LoginModule} state. 97 * 98 * @param options options specified in the login 99 * {@code Configuration} for this particular 100 * {@code LoginModule}. 101 */ 102 public void initialize(Subject subject, CallbackHandler callbackHandler, 103 Map<String,?> sharedState, 104 Map<String,?> options) 105 { 106 107 this.subject = subject; 108 this.callbackHandler = callbackHandler; 109 this.sharedState = sharedState; 110 this.options = options; 111 112 // initialize any configured options 113 debug = "true".equalsIgnoreCase((String)options.get("debug")); 114 } 115 116 /** 117 * Authenticate the user (first phase). 118 * 119 * <p> The implementation of this method attempts to retrieve the user's 120 * Solaris {@code Subject} information by making a native Solaris 121 * system call. 122 * 123 * @exception FailedLoginException if attempts to retrieve the underlying 124 * system information fail. 125 * 126 * @return true in all cases (this {@code LoginModule} 127 * should not be ignored). 128 */ 129 @SuppressWarnings("removal") 130 public boolean login() throws LoginException { 131 132 long[] solarisGroups = null; 133 134 try { 135 ss = new SolarisSystem(); 136 } catch (UnsatisfiedLinkError ule) { 137 succeeded = false; 138 throw new FailedLoginException 139 ("Failed in attempt to import " + 140 "the underlying system identity information" + 141 " on " + System.getProperty("os.name")); 142 } 143 userPrincipal = new SolarisPrincipal(ss.getUsername()); 144 UIDPrincipal = new SolarisNumericUserPrincipal(ss.getUid()); 145 GIDPrincipal = new SolarisNumericGroupPrincipal(ss.getGid(), true); 146 if (ss.getGroups() != null && ss.getGroups().length > 0) 147 solarisGroups = ss.getGroups(); 148 for (int i = 0; i < solarisGroups.length; i++) { 149 SolarisNumericGroupPrincipal ngp = 150 new SolarisNumericGroupPrincipal 151 (solarisGroups[i], false); 152 if (!ngp.getName().equals(GIDPrincipal.getName())) 153 supplementaryGroups.add(ngp); 154 } 155 if (debug) { 156 System.out.println("\t\t[SolarisLoginModule]: " + 157 "succeeded importing info: "); 158 System.out.println("\t\t\tuid = " + ss.getUid()); 159 System.out.println("\t\t\tgid = " + ss.getGid()); 160 solarisGroups = ss.getGroups(); 161 for (int i = 0; i < solarisGroups.length; i++) { 162 System.out.println("\t\t\tsupp gid = " + solarisGroups[i]); 163 } 164 } 165 succeeded = true; 166 return true; 167 } 168 169 /** 170 * Commit the authentication (second phase). 171 * 172 * <p> This method is called if the LoginContext's 173 * overall authentication succeeded 174 * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules 175 * succeeded). 176 * 177 * <p> If this LoginModule's own authentication attempt 178 * succeeded (the importing of the Solaris authentication information 179 * succeeded), then this method associates the Solaris Principals 180 * with the {@code Subject} currently tied to the 181 * {@code LoginModule}. If this LoginModule's 182 * authentication attempted failed, then this method removes 183 * any state that was originally saved. 184 * 185 * @exception LoginException if the commit fails 186 * 187 * @return true if this LoginModule's own login and commit attempts 188 * succeeded, or false otherwise. 189 */ 190 public boolean commit() throws LoginException { 191 if (succeeded == false) { 192 if (debug) { 193 System.out.println("\t\t[SolarisLoginModule]: " + 194 "did not add any Principals to Subject " + 195 "because own authentication failed."); 196 } 197 return false; 198 } 199 if (subject.isReadOnly()) { 200 throw new LoginException ("Subject is Readonly"); 201 } 202 if (!subject.getPrincipals().contains(userPrincipal)) 203 subject.getPrincipals().add(userPrincipal); 204 if (!subject.getPrincipals().contains(UIDPrincipal)) 205 subject.getPrincipals().add(UIDPrincipal); 206 if (!subject.getPrincipals().contains(GIDPrincipal)) 207 subject.getPrincipals().add(GIDPrincipal); 208 for (int i = 0; i < supplementaryGroups.size(); i++) { 209 if (!subject.getPrincipals().contains(supplementaryGroups.get(i))) 210 subject.getPrincipals().add(supplementaryGroups.get(i)); 211 } 212 213 if (debug) { 214 System.out.println("\t\t[SolarisLoginModule]: " + 215 "added SolarisPrincipal,"); 216 System.out.println("\t\t\t\tSolarisNumericUserPrincipal,"); 217 System.out.println("\t\t\t\tSolarisNumericGroupPrincipal(s),"); 218 System.out.println("\t\t\t to Subject"); 219 } 220 221 commitSucceeded = true; 222 return true; 223 } 224 225 226 /** 227 * Abort the authentication (second phase). 228 * 229 * <p> This method is called if the LoginContext's 230 * overall authentication failed. 231 * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules 232 * did not succeed). 233 * 234 * <p> This method cleans up any state that was originally saved 235 * as part of the authentication attempt from the {@code login} 236 * and {@code commit} methods. 237 * 238 * @exception LoginException if the abort fails 239 * 240 * @return false if this LoginModule's own login and/or commit attempts 241 * failed, and true otherwise. 242 */ 243 @SuppressWarnings("removal") 244 public boolean abort() throws LoginException { 245 if (debug) { 246 System.out.println("\t\t[SolarisLoginModule]: " + 247 "aborted authentication attempt"); 248 } 249 250 if (succeeded == false) { 251 return false; 252 } else if (succeeded == true && commitSucceeded == false) { 253 254 // Clean out state 255 succeeded = false; 256 ss = null; 257 userPrincipal = null; 258 UIDPrincipal = null; 259 GIDPrincipal = null; 260 supplementaryGroups = 261 new LinkedList<SolarisNumericGroupPrincipal>(); 262 } else { 263 // overall authentication succeeded and commit succeeded, 264 // but someone else's commit failed 265 logout(); 266 } 267 return true; 268 } 269 270 /** 271 * Logout the user 272 * 273 * <p> This method removes the Principals associated 274 * with the {@code Subject}. 275 * 276 * @exception LoginException if the logout fails 277 * 278 * @return true in all cases (this {@code LoginModule} 279 * should not be ignored). 280 */ 281 @SuppressWarnings("removal") 282 public boolean logout() throws LoginException { 283 if (debug) { 284 System.out.println("\t\t[SolarisLoginModule]: " + 285 "Entering logout"); 286 } 287 if (subject.isReadOnly()) { 288 throw new LoginException ("Subject is Readonly"); 289 } 290 // remove the added Principals from the Subject 291 subject.getPrincipals().remove(userPrincipal); 292 subject.getPrincipals().remove(UIDPrincipal); 293 subject.getPrincipals().remove(GIDPrincipal); 294 for (int i = 0; i < supplementaryGroups.size(); i++) { 295 subject.getPrincipals().remove(supplementaryGroups.get(i)); 296 } 297 298 // clean out state 299 ss = null; 300 succeeded = false; 301 commitSucceeded = false; 302 userPrincipal = null; 303 UIDPrincipal = null; 304 GIDPrincipal = null; 305 supplementaryGroups = new LinkedList<SolarisNumericGroupPrincipal>(); 306 307 if (debug) { 308 System.out.println("\t\t[SolarisLoginModule]: " + 309 "logged out Subject"); 310 } 311 return true; 312 } 313 }