1 7 8 package com.sun.jmx.remote.security; 9 10 import java.io.IOException ; 11 import java.security.AccessController ; 12 import java.security.Principal ; 13 import java.security.PrivilegedAction ; 14 import java.security.PrivilegedActionException ; 15 import java.security.PrivilegedExceptionAction ; 16 import java.util.Collections ; 17 import java.util.HashMap ; 18 import java.util.Map ; 19 import java.util.Properties ; 20 import javax.management.remote.JMXPrincipal ; 21 import javax.management.remote.JMXAuthenticator ; 22 import javax.security.auth.AuthPermission ; 23 import javax.security.auth.Subject ; 24 import javax.security.auth.callback.*; 25 import javax.security.auth.login.AppConfigurationEntry ; 26 import javax.security.auth.login.Configuration ; 27 import javax.security.auth.login.LoginContext ; 28 import javax.security.auth.login.LoginException ; 29 import javax.security.auth.spi.LoginModule ; 30 import com.sun.jmx.remote.util.ClassLogger; 31 import com.sun.jmx.remote.util.EnvHelp; 32 33 60 public final class JMXPluggableAuthenticator implements JMXAuthenticator { 61 62 72 public JMXPluggableAuthenticator(Map env) { 73 74 String loginConfigName = null; 75 String passwordFile = null; 76 77 if (env != null) { 78 loginConfigName = (String ) env.get(LOGIN_CONFIG_PROP); 79 passwordFile = (String ) env.get(PASSWORD_FILE_PROP); 80 } 81 82 try { 83 84 if (loginConfigName != null) { 85 loginContext = 87 new LoginContext (loginConfigName, new JMXCallbackHandler()); 88 89 } else { 90 SecurityManager sm = System.getSecurityManager(); 92 if (sm != null) { 93 sm.checkPermission( 94 new AuthPermission ("createLoginContext." + 95 LOGIN_CONFIG_NAME)); 96 } 97 98 final String pf = passwordFile; 99 try { 100 loginContext = (LoginContext ) AccessController.doPrivileged( 101 new PrivilegedExceptionAction () { 102 public Object run() throws LoginException { 103 return new LoginContext ( 104 LOGIN_CONFIG_NAME, 105 null, 106 new JMXCallbackHandler(), 107 new FileLoginConfig(pf)); 108 } 109 }); 110 } catch (PrivilegedActionException pae) { 111 throw (LoginException ) pae.getException(); 112 } 113 } 114 115 } catch (LoginException le) { 116 authenticationFailure("authenticate", le); 117 118 } catch (SecurityException se) { 119 authenticationFailure("authenticate", se); 120 } 121 } 122 123 139 public Subject authenticate(Object credentials) { 140 if (!(credentials instanceof String [])) { 143 if (credentials == null) 145 authenticationFailure("authenticate", "Credentials required"); 146 147 final String message = 148 "Credentials should be String[] instead of " + 149 credentials.getClass().getName(); 150 authenticationFailure("authenticate", message); 151 } 152 final String [] aCredentials = (String []) credentials; 155 if (aCredentials.length != 2) { 156 final String message = 157 "Credentials should have 2 elements not " + 158 aCredentials.length; 159 authenticationFailure("authenticate", message); 160 } 161 username = (String ) aCredentials[0]; 165 password = (String ) aCredentials[1]; 166 if (username == null || password == null) { 167 final String message = "Username or password is null"; 168 authenticationFailure("authenticate", message); 169 } 170 171 try { 173 loginContext.login(); 174 final Subject subject = loginContext.getSubject(); 175 AccessController.doPrivileged(new PrivilegedAction () { 176 public Object run() { 177 subject.setReadOnly(); 178 return null; 179 } 180 }); 181 182 return subject; 183 184 } catch (LoginException le) { 185 authenticationFailure("authenticate", le); 186 } 187 return null; 188 } 189 190 private static void authenticationFailure(String method, String message) 191 throws SecurityException { 192 final String msg = "Authentication failed! " + message; 193 final SecurityException e = new SecurityException (msg); 194 logException(method, msg, e); 195 throw e; 196 } 197 198 private static void authenticationFailure(String method, 199 Exception exception) 200 throws SecurityException { 201 String msg; 202 SecurityException se; 203 if (exception instanceof SecurityException ) { 204 msg = exception.getMessage(); 205 se = (SecurityException ) exception; 206 } else { 207 msg = "Authentication failed! " + exception.getMessage(); 208 final SecurityException e = new SecurityException (msg); 209 EnvHelp.initCause(e, exception); 210 se = e; 211 } 212 logException(method, msg, se); 213 throw se; 214 } 215 216 private static void logException(String method, 217 String message, 218 Exception e) { 219 if (logger.traceOn()) { 220 logger.trace(method, message); 221 } 222 if (logger.debugOn()) { 223 logger.debug(method, e); 224 } 225 } 226 227 private LoginContext loginContext; 228 private String username; 229 private String password; 230 private static final String LOGIN_CONFIG_PROP = 231 "jmx.remote.x.login.config"; 232 private static final String LOGIN_CONFIG_NAME = "JMXPluggableAuthenticator"; 233 private static final String PASSWORD_FILE_PROP = 234 "jmx.remote.x.password.file"; 235 private static final ClassLogger logger = 236 new ClassLogger("javax.management.remote.misc", LOGIN_CONFIG_NAME); 237 238 244 private final class JMXCallbackHandler implements CallbackHandler { 245 246 249 public void handle(Callback[] callbacks) 250 throws IOException , UnsupportedCallbackException { 251 252 for (int i = 0; i < callbacks.length; i++) { 253 if (callbacks[i] instanceof NameCallback) { 254 ((NameCallback)callbacks[i]).setName(username); 255 256 } else if (callbacks[i] instanceof PasswordCallback) { 257 ((PasswordCallback)callbacks[i]) 258 .setPassword(password.toCharArray()); 259 260 } else { 261 throw new UnsupportedCallbackException 262 (callbacks[i], "Unrecognized Callback"); 263 } 264 } 265 } 266 } 267 268 277 private static class FileLoginConfig extends Configuration { 278 279 private static AppConfigurationEntry [] entries; 281 282 private static final String FILE_LOGIN_MODULE = 284 FileLoginModule.class.getName(); 285 286 private static final String PASSWORD_FILE_OPTION = "passwordFile"; 288 289 295 public FileLoginConfig(String passwordFile) { 296 297 Map options; 298 if (passwordFile != null) { 299 options = new HashMap (1); 300 options.put(PASSWORD_FILE_OPTION, passwordFile); 301 } else { 302 options = Collections.EMPTY_MAP; 303 } 304 305 entries = new AppConfigurationEntry [] { 306 new AppConfigurationEntry (FILE_LOGIN_MODULE, 307 AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, 308 options) 309 }; 310 } 311 312 315 public AppConfigurationEntry [] getAppConfigurationEntry(String name) { 316 317 return name.equals(LOGIN_CONFIG_NAME) ? entries : null; 318 } 319 320 323 public void refresh() { 324 } 326 } 327 328 } 329 | Popular Tags |