LoginContextDriverpublic class LoginContextDriver extends Object This class is invoked implicitly by the server to log in the user
information that was sent on the wire by the client. Clients will
use the doClientLogin method to simulate authentication to the
server. |
Fields Summary |
---|
private static final Logger | _logger | private static final com.sun.enterprise.security.auth.login.ServerLoginCallbackHandler | dummyCallback | private static final String | CLIENT_JAAS_PASSWORD | private static final String | CLIENT_JAAS_CERTIFICATE | public static final String | CERT_REALMNAME | public static final com.sun.enterprise.security.audit.AuditManager | AUDIT_MANAGER |
Constructors Summary |
---|
private LoginContextDriver()This class cannot be instantiated
|
Methods Summary |
---|
private static void | doAnonLogin()A special case login for anonymous credentials (no login info).
// instance of anononymous credential login with guest
SecurityContext.setUnauthenticatedContext();
if(_logger.isLoggable(Level.FINE)){
_logger.log(Level.FINE,"Set anonymous security context.");
}
| private static void | doCertificateLogin(javax.security.auth.Subject s)A special case login for handling X509CertificateCredential.
This does not get triggered based on current RI code. See X500Login.
if(_logger.isLoggable(Level.FINE)){
_logger.log(Level.FINE, "Processing X509 certificate login.");
}
String realm = CertificateRealm.AUTH_TYPE;
String user = null;
try{
Object obj = getPublicCredentials(s, X509CertificateCredential.class);
X509CertificateCredential xp = (X509CertificateCredential) obj;
user = xp.getAlias();
if(_logger.isLoggable(Level.FINE)){
_logger.log(Level.FINE,"Set security context as user: "+user);
}
setSecurityContext(user, s, realm);
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(user, realm, true);
}
} catch(LoginException le){
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(user, realm, false);
}
throw le;
}
| public static javax.security.auth.Subject | doClientLogin(int type, javax.security.auth.callback.CallbackHandler jaasHandler)Perform login on the client side.
It just simulates the login on the client side.
The method uses the callback handlers and generates correct
credential information that will be later sent to the server
final javax.security.auth.callback.CallbackHandler handler =
jaasHandler;
// the subject will actually be filled in with a PasswordCredential
// required by the csiv2 layer in the LoginModule.
// we create the dummy credential here and call the
// set security context. Thus, we have 2 credentials, one each for
// the csiv2 layer and the other for the RI.
final Subject subject = new Subject();
if (type == AppContainer.USERNAME_PASSWORD){
AppservAccessController.doPrivileged(new PrivilegedAction() {
public java.lang.Object run() {
try{
LoginContext lg =
new LoginContext(CLIENT_JAAS_PASSWORD,
subject, handler);
lg.login();
}catch(javax.security.auth.login.LoginException e){
throw (LoginException)
new LoginException(e.toString()).initCause(e);
}
return null;
}
});
postClientAuth(subject, PasswordCredential.class);
return subject;
} else if (type == AppContainer.CERTIFICATE){
AppservAccessController.doPrivileged(new PrivilegedAction() {
public java.lang.Object run() {
try{
LoginContext lg =
new LoginContext(CLIENT_JAAS_CERTIFICATE,
subject, handler);
lg.login();
}catch(javax.security.auth.login.LoginException e){
throw (LoginException)
new LoginException(e.toString()).initCause(e);
}
return null;
}
});
postClientAuth(subject, X509CertificateCredential.class);
return subject;
} else if (type == AppContainer.ALL){
AppservAccessController.doPrivileged(new PrivilegedAction() {
public java.lang.Object run() {
try{
LoginContext lgup =
new LoginContext(CLIENT_JAAS_PASSWORD,
subject, handler);
LoginContext lgc =
new LoginContext(CLIENT_JAAS_CERTIFICATE,
subject, handler);
lgup.login();
postClientAuth(subject, PasswordCredential.class);
lgc.login();
postClientAuth(subject,
X509CertificateCredential.class);
}catch(javax.security.auth.login.LoginException e){
throw (LoginException)
new LoginException(e.toString()).initCause(e);
}
return null;
}
});
return subject;
} else{
AppservAccessController.doPrivileged(new PrivilegedAction() {
public java.lang.Object run() {
try{
LoginContext lg =
new LoginContext(CLIENT_JAAS_PASSWORD,
subject, handler);
lg.login();
postClientAuth(subject, PasswordCredential.class);
}catch(javax.security.auth.login.LoginException e){
throw (LoginException)
new LoginException(e.toString()).initCause(e);
}
return null;
}
});
return subject;
}
| public static void | doClientLogout()Perform logout on the client side.
unsetClientSecurityContext();
| private static void | doGSSUPLogin(javax.security.auth.Subject s)A special case login for GSSUPName credentials.
if(_logger.isLoggable(Level.FINE)){
_logger.fine("Processing GSSUP login.");
}
String user = null;
String realm = Realm.getDefaultRealm();
try{
Object obj = getPublicCredentials(s, GSSUPName.class);
user = ((GSSUPName)obj).getUser();
setSecurityContext(user, s, realm);
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(user, realm, true);
}
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("GSSUP login succeeded for : " + user);
}
} catch (LoginException le){
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(user, realm, false);
}
throw le;
}
| private static void | doPasswordLogin(javax.security.auth.Subject subject)Log in subject with PasswordCredential. This is a generic login
which applies to all login mechanisms which process PasswordCredential.
In other words, any mechanism which receives an actual username, realm
and password set from the client.
The realm contained in the credential is checked, and a JAAS
LoginContext is created using a context name obtained from the
appropriate Realm instance. The applicable JAAS LoginModule
is initialized (based on the jaas login configuration) and login()
is invoked on it.
RI code makes several assumptions which are retained here:
- The PasswordCredential is stored as a private credential of
the subject.
- There is only one such credential present (actually, only
the first one is relevant if more are present).
final Subject s = subject;
Object obj = getPrivateCredentials(s, PasswordCredential.class);
assert obj != null;
PasswordCredential p = (PasswordCredential) obj;
String user = p.getUser();
String pwd = p.getPassword();
String realm = p.getRealm();
String jaasCtx = null;
try {
jaasCtx = Realm.getInstance(realm).getJAASContext();
} catch(Exception ex) {
if( ex instanceof LoginException )
throw (LoginException)ex;
else
throw (LoginException)new LoginException(ex.toString()).initCause(ex);
}
assert user != null;
assert pwd != null;
assert realm != null;
assert jaasCtx != null;
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("Logging in user [" + user + "] into realm: " +
realm + " using JAAS module: "+jaasCtx);
}
try {
// A dummyCallback is used to satisfy JAAS but it is never used.
// name/pwd info is already contained in Subject's Credential
LoginContext lg = new LoginContext(jaasCtx, s, dummyCallback);
lg.login();
} catch (Exception e) {
if (_logger.isLoggable(Level.INFO)) {
_logger.log(Level.INFO, "java_security.audit_auth_refused",
user);
}
if (_logger.isLoggable(Level.FINEST)) {
_logger.log(Level.FINEST, "doPasswordLogin fails", e);
}
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(user, realm, false);
}
if( e instanceof LoginException )
throw (LoginException)e;
else
throw (LoginException)
new LoginException("Login failed: " + e.toString()).initCause(e);
}
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(user, realm, true);
}
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("Password login succeeded for : " + user);
}
setSecurityContext(user, s, realm);
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "Set security context as user: "+user);
}
| private static void | doX500Login(javax.security.auth.Subject s)A special case login for X500Name credentials.
This is invoked for certificate login because the containers
extract the X.500 name from the X.509 certificate before calling
into this class.
if(_logger.isLoggable(Level.FINE)){
_logger.fine("Processing X.500 name login.");
}
String user = null;
String realm_name = null;
try{
X500Name x500name = (X500Name)getPublicCredentials(s, X500Name.class);
user = x500name.getName();
// In the RI-inherited implementation this directly creates
// some credentials and sets the security context. This means
// that the certificate realm does not get an opportunity to
// process the request. While the realm will not do any
// authentication (already done by this point) it can choose
// to adjust the groups or principal name or other variables
// of the security context. Of course, bug 4646134 needs to be
// kept in mind at all times.
Realm realm = Realm.getInstance(CertificateRealm.AUTH_TYPE);
if (realm instanceof CertificateRealm) { // should always be true
CertificateRealm certRealm = (CertificateRealm)realm;
certRealm.authenticate(s, x500name);
realm_name = CertificateRealm.AUTH_TYPE;
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(user, realm_name, true);
}
} else {
_logger.warning("certlogin.badrealm");
setSecurityContext(user, s, realm_name);
realm_name = realm.getName();
}
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("X.500 name login succeeded for : " + user);
}
} catch (LoginException le){
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(user, realm_name, false);
}
throw le;
} catch (Exception ex) {
throw (LoginException)new LoginException(ex.toString()).initCause(ex);
}
| private static java.lang.Object | getPrivateCredentials(javax.security.auth.Subject subject, java.lang.Class cls)Retrieve a private credential of the given type (java class) from the
subject.
This method retains the RI assumption that only the first
credential of the given type is used.
final Subject s = subject;
final Class cl = cls;
final Set credset = (Set)
AppservAccessController.doPrivileged(new PrivilegedAction() {
public java.lang.Object run() {
return
s.getPrivateCredentials(cl);
}
});
final Iterator iter = credset.iterator();
if (!iter.hasNext()) {
String credmsg = cls.toString();
if(_logger.isLoggable(Level.FINER)){
_logger.finer("Expected private credential of type: "+
credmsg + " but none found.");
}
throw new LoginException("Expected private credential of type: "+
credmsg + " but none found.");
}
// retrieve only first credential of give type
Object obj = null;
try{
obj = AppservAccessController.doPrivileged(new PrivilegedAction(){
public java.lang.Object run(){
return iter.next();
}
});
} catch (Exception e){
// should never come here
if( e instanceof LoginException )
throw (LoginException)e;
else
throw (LoginException)
new LoginException("Failed to retrieve private credential: "+
e.toString()).initCause(e);
}
return obj;
| private static java.lang.Object | getPublicCredentials(javax.security.auth.Subject s, java.lang.Class cls)Retrieve a public credential of the given type (java class) from the
subject.
This method retains the RI assumption that only the first
credential of the given type is used.
Set credset = s.getPublicCredentials(cls);
final Iterator iter = credset.iterator();
if(!iter.hasNext()) {
String credmsg = cls.toString();
if(_logger.isLoggable(Level.FINER)){
_logger.finer("Expected public credentials of type : " +
credmsg + " but none found.");
}
throw new LoginException("Expected public credential of type: "+
credmsg + " but none found.");
}
Object obj = null;
try{
obj = AppservAccessController.doPrivileged(new PrivilegedAction(){
public java.lang.Object run(){
return iter.next();
}
});
} catch (Exception e){
// should never come here
if( e instanceof LoginException )
throw (LoginException)e;
else
throw (LoginException)
new LoginException("Failed to retrieve public credential: "+
e.toString()).initCause(e);
}
return obj;
| public static javax.security.auth.Subject | jmacLogin(javax.security.auth.Subject subject, java.lang.String username, java.lang.String password, java.lang.String realmName)Performs login for JMAC security. The difference between this
method and others is that it just verifies whether the login will succeed
in the given realm.
It does not set the result of the authentication in the appserver runtime
environment
A silent return from this method means that the given user succeeding in
authenticating with the given password in the given realm
if(realmName == null || !(Realm.isValidRealm(realmName))){
realmName = Realm.getDefaultRealm();
}
if (subject == null) {
subject = new Subject();
}
final Subject fs = subject;
final PasswordCredential pc =
new PasswordCredential(username, password, realmName);
AppservAccessController.doPrivileged(new PrivilegedAction(){
public java.lang.Object run(){
fs.getPrivateCredentials().add(pc);
return fs;
}
});
String jaasCtx = null;
try {
jaasCtx = Realm.getInstance(realmName).getJAASContext();
} catch(Exception ex) {
if( ex instanceof LoginException )
throw (LoginException)ex;
else
throw (LoginException)
new LoginException(ex.toString()).initCause(ex);
}
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("jmac login user [" + username + "] into realm: " +
realmName + " using JAAS module: "+jaasCtx);
}
try{
// A dummyCallback is used to satisfy JAAS but it is never used.
// name/pwd info is already contained in Subject's Credential
LoginContext lg = new LoginContext(jaasCtx, fs, dummyCallback);
lg.login();
} catch (Exception e) {
if (_logger.isLoggable(Level.INFO)) {
_logger.log(Level.INFO, "java_security.audit_auth_refused",
username);
}
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(username, realmName, false);
}
if( e instanceof LoginException )
throw (LoginException)e;
else
throw (LoginException)
new LoginException("Login failed: " + e.toString()).initCause(e);
}
if(AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(username, realmName, true);
}
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("jmac Password login succeeded for : " + username);
}
return subject;
// do not set the security Context
| public static javax.security.auth.Subject | jmacLogin(javax.security.auth.Subject subject, javax.security.auth.x500.X500Principal x500Principal)
if (subject == null) {
subject = new Subject();
}
final Subject fs = subject;
String userName = "";
try {
final X500Name x500Name = new X500Name(
x500Principal.getName(X500Principal.RFC1779));
userName = x500Name.toString();
AppservAccessController.doPrivileged(new PrivilegedAction(){
public java.lang.Object run(){
fs.getPublicCredentials().add(x500Name);
return fs;
}
});
Realm realm = Realm.getInstance(CertificateRealm.AUTH_TYPE);
CertificateRealm certRealm = (CertificateRealm)realm;
certRealm.authenticate(fs, x500Name);
} catch(Exception ex) {
if (_logger.isLoggable(Level.INFO)) {
_logger.log(Level.INFO, "java_security.audit_auth_refused",
userName);
}
if (AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(userName,
CertificateRealm.AUTH_TYPE, false);
}
if (ex instanceof LoginException) {
throw (LoginException)ex;
} else {
throw (LoginException)
new LoginException(ex.toString()).initCause(ex);
}
}
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("jmac cert login succeeded for: " + userName);
}
if (AUDIT_MANAGER.isAuditOn()){
AUDIT_MANAGER.authentication(userName,
CertificateRealm.AUTH_TYPE, true);
}
// do not set the security Context
return subject;
| public static void | login(java.lang.String username, java.lang.String password, java.lang.String realmName)This method is just a convenience wrapper for
login(Subject, Class) method. It will construct a
PasswordCredential class.
if(realmName == null || !(Realm.isValidRealm(realmName))){
realmName = Realm.getDefaultRealm();
}
final Subject fs = new Subject();
final PasswordCredential pc =
new PasswordCredential(username, password, realmName);
AppservAccessController.doPrivileged(new PrivilegedAction(){
public java.lang.Object run(){
fs.getPrivateCredentials().add(pc);
return fs;
}
});
LoginContextDriver.login(fs, PasswordCredential.class);
| public static void | login(javax.security.auth.Subject subject, java.lang.Class cls)This method performs the login on the server side.
This method is the main login method for S1AS. It is called
with a Subject and the type (class) of credential which should
be checked. The Subject must contain a credential of the
specified type or login will fail.
While the implementation has been cleaned up, the login
process still consists of a number of special cases which are
treated separately at the realm level. In the future tighter
JAAS integration could clean some of this up.
The following credential types are recognized at this time:
- PasswordCredential - This is the general case for all login
methods which rely on the client providing a name and password.
It can be used with any realms/JAAS login modules which expect
such data (e.g. file realm, LDAP realm, UNIX realm)
- X509CertificateCredential - Special case for SSL client auth.
Here authentication has already been done by the SSL subsystem
so this login only creates a security context based on the
certificate data.
- AnonCredential - Unauthenticated session, set anonymous security
context.
- GSSUPName - Retrieve user and realm and set security context.
- X500Name - Retrieve user and realm and set security context.
if (_logger.isLoggable(Level.FINEST)) {
_logger.log(Level.FINEST,
"Processing login with credentials of type: "+
cls.toString());
}
if(cls.equals(PasswordCredential.class)) {
doPasswordLogin(subject);
} else if (cls.equals(X509CertificateCredential.class)) {
doCertificateLogin(subject);
} else if (cls.equals(AnonCredential.class)) {
doAnonLogin();
} else if (cls.equals(GSSUPName.class)) {
doGSSUPLogin(subject);
} else if (cls.equals(X500Name.class)) {
doX500Login(subject);
} else {
_logger.log(Level.INFO, "java_security.unknown_credential",
cls.toString());
throw new
LoginException("Unknown credential type, cannot login.");
}
| public static void | loginPrincipal(java.lang.String username, java.lang.String realmName)This method is used for logging in a run As principal. It creates
a JAAS subject whose credential is to type GSSUPName.
This is used primarily for runas
// no realm provided, assuming default
if(realmName == null || realmName.length() == 0){
realmName = Realm.getDefaultRealm();
}
final Subject s = new Subject();
final com.sun.enterprise.deployment.PrincipalImpl p
= new com.sun.enterprise.deployment.PrincipalImpl(username);
final GSSUPName name = new GSSUPName(username, realmName);
AppservAccessController.doPrivileged(new PrivilegedAction() {
public java.lang.Object run() {
s.getPrincipals().add(p);
s.getPublicCredentials().add(name);
return null;
}
});
setSecurityContext(username, s, realmName);
| public static void | logout()This method logs out the user by clearing the security context.
unsetSecurityContext();
| private static void | postClientAuth(javax.security.auth.Subject subject, java.lang.Class clazz)Extract the relevant username and realm information from the
subject and sets the correct state in the security context. The
relevant information is set into the Thread Local Storage from
which then is extracted to send over the wire.
final Class clas = clazz;
final Subject fs = subject;
Set credset =
(Set) AppservAccessController.doPrivileged(new PrivilegedAction() {
public java.lang.Object run() {
if(_logger.isLoggable(Level.FINEST)){
_logger.log(Level.FINEST,"LCD post login subject :" + fs);
}
return fs.getPrivateCredentials(clas);
}
});
final Iterator iter = credset.iterator();
while(iter.hasNext()) {
Object obj = null;
try{
obj = AppservAccessController.doPrivileged(new PrivilegedAction(){
public java.lang.Object run(){
return iter.next();
}
});
} catch (Exception e){
// should never come here
_logger.log(Level.SEVERE,
"java_security.accesscontroller_action_exception",
e);
}
if(obj instanceof PasswordCredential) {
PasswordCredential p = (PasswordCredential) obj;
String user = p.getUser();
if(_logger.isLoggable(Level.FINEST)){
String realm = p.getRealm();
_logger.log(Level.FINEST,"In LCD user-pass login:" +
user +" realm :" + realm);
}
setClientSecurityContext(user, fs);
return;
} else if (obj instanceof X509CertificateCredential){
X509CertificateCredential p = (X509CertificateCredential) obj;
String user = p.getAlias();
if(_logger.isLoggable(Level.FINEST)){
String realm = p.getRealm();
_logger.log(Level.FINEST,"In LCD cert-login::" +
user +" realm :" + realm);
}
setClientSecurityContext(user, fs);
return;
}
}
| private static void | setClientSecurityContext(java.lang.String username, javax.security.auth.Subject subject)Sets the security context on the appclient side.
It sets the relevant information into the TLS
ClientSecurityContext securityContext =
new ClientSecurityContext(username, subject);
ClientSecurityContext.setCurrent(securityContext);
| private static void | setSecurityContext(java.lang.String userName, javax.security.auth.Subject subject, java.lang.String realm)This method sets the security context on the current Thread Local
Storage
SecurityContext securityContext =
new SecurityContext(userName, subject, realm);
SecurityContext.setCurrent(securityContext);
| private static void | unsetClientSecurityContext()Unsets the current appclient security context on the Thread
Local Storage
ClientSecurityContext.setCurrent(null);
| private static void | unsetSecurityContext()Set the current security context on the Thread Local Storage to null.
SecurityContext.setCurrent((SecurityContext)null);
|
|