Dashboard > JJGuidelines > Home > Appendix B - Guidelines Rules > B.8. JAAS rules
JJGuidelines Log In | Sign Up   View a printable version of the current page.
B.8. JAAS rules
Added by Alexander Bollaert, last edited by Alexander Bollaert on Jan 10, 2007  (view change)

JAAS rules

Overview

Table B.8. JAAS rules

Rules
JAAS_001: Do Not Add A Principal Or Credential To A Subject At Login Time In A Login Module
JAAS_002: Only Clean A Principal Or Credential Previously Added To A Non Readonly Subject At Logout Time In A Login Module
JAAS_003: Return false From A login Method Only To Indicate To Ignore The Login Module
JAAS_004: Do Not Interact With A User Directly In A Login Module
JAAS_005: Ask For Credentials Only Once When Combining Multiple Login Modules
JAAS_006: Add A Debug Option To A Login Module
JAAS_007: Make A Principal Serializable
JAAS_008: Use Principals To Name Groups And Roles
JAAS_009: Use A PrincipalComparator To Structure Principals Hierarchically
JAAS_010: Use A PriviledgedExceptionAction To Raise Checked Exceptions From Secured Code Fragments
JAAS_011: Use The doAsPriviledged Method Of A Subject Instead Of The doAs Method

JAAS_001: Do Not Add A Principal Or Credential To A Subject At Login Time In A Login Module

If the application instructs JAAS to login a 2-phase process is triggered:

  • First, one by one, on each LoginModule the login method is invoked. The outcome of login should be stored by each login module privately.
  • If all login invocations returned true, the distinct login modules are instructed to commit: this is the correct time to link relevant Principal and Credential objects to the Subject.

WRONG

public class MyLoginModule {
	private Subject s;

	public boolean login() throws LoginException {
		// Declare and initialize boolean trustedUser
		if (trustedUser) {
			Set principals = Subject.getPrincipals();
			principals.add(new MyPrincipal("jcs"));
		}
		return true;
	}

	public boolean commit() {
	}
}

RIGHT

public class MyLoginModule {
	private Subject s;

	private boolean trustedUser;

	public boolean login() throws LoginException {
		trustedUser = true;
		return true;
	}

	public boolean commit() throws LoginException {
		if (trustedUser) {
			Set principals = Subject.getPrincipals();
			principals.add(new MyPrincipal("jcs"));
		}
	}
}

JAAS_002: Only Clean A Principal Or Credential Previously Added To A Non Readonly Subject At Logout Time In A Login Module

Each LoginModule uses well-defined Principals. LoginModules should not destroy each other's Principals.

WRONG

public class MyLoginModule {
	private Subject s;

	public boolean logout() throws LoginException {
		s.getPrincipals().clear();
	}
}

RIGHT

public class MyLoginModule {
	private Subject s;

	public boolean logout() {
		Set mine = s.getPrincipals(MyPrincipal.class);
		s.getPrincipals().removeAll(mine);
	}
}

JAAS_003: Return false From A login Method Only To Indicate To Ignore The Login Module

If a user is not trusted by a login module, the latter should not return false but raise a LoginException at login-time.

WRONG

public class MyLoginModule {
	public boolean login() throws LoginException { 
		// ...
		return trustedUser;
	}
}

RIGHT

public class MyLoginModule {
	public boolean login() throws LoginException { // ...
		throw new LoginException("User not trusted");
	}
}

JAAS_004: Do Not Interact With A User Directly In A Login Module

At no single moment a login module may directly contact the subject to authenticate: at all times a callback should be used to do so. Numerous callback-implementations are available, even generic TextInputCallback and TextOutputCallback.

WRONG

public class MyLoginModule {
	public boolean login() throws LoginException {
		System.out.println("Please provide VISA");
		BufferedReader stdin = new BufferedReader(new InputStreamReader(
				System.in));
		String visa = stdin.readLine();
	}
}

RIGHT

public class MyLoginModule {
	private CallbackHandler cbh;

	public boolean login() throws LoginException {
		Callback visaCb = new TextInputCallback("Please provide VISA");
		cbh.handle(new Callback[] { visaCb });
		String visa = visaCb.getText();
	}
}

JAAS_005: Ask For Credentials Only Once When Combining Multiple Login Modules

LoginModule should verify that credentials were not yet prompted for by another other modules. This dramatically enhances user-experience. The shared options Map has well defined entries to contain username and password:

  • javax.security.auth.login.name
  • javax.security.auth.login.password

WRONG

public class MyLoginModule {
	private CallbackHandler cbh;

	public boolean login() throws LoginException {
		cbh.handle(/* ... */);
	}
}

RIGHT

public class MyLoginModule {
	private CallbackHandler cbh;

	private Map sharedState;

	public boolean login() throws LoginException {
		String uid = (String) sharedState.get("javax.security.auth.login.name");
		if ((uid == null)) {
			cbh.handle(new CallBack[] {/* ... */});
		}
	}
}

JAAS_006: Add A Debug Option To A Login Module

Login modules function in the background, hiding a lot of detail. Both when doing development and debugging authentication-issues later on it, it is convenient to be able to turn on detailed debugging info. Consider this as lightweight debugging, serious bugs should always be cleared by attaching a JVMDI-enabled debugger to the application.

RIGHT

jaas.config

Foo { 
    be.jcs.auth.MyLoginModule REQUIRED debug=true; 
}

MyLoginModule.java

public class MyLoginModule {
	private Map options;

	public boolean login() throws LoginException {
		if (Boolean.valueOf((String) options.get("debug")).booleanValue()) {
			logger.debug("Authenticated " + username);
		}
	}
}

JAAS_007: Make A Principal Serializable

At all times custom Principal implementations should implement Serializable.

WRONG

public class MyPrincipal implements Principal {
	private String name;

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

RIGHT

public class MyPrincipal implements Principal, Serializable {
	private String name;

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

JAAS_008: Use Principals To Name Groups And Roles

It is convenient to associate a Subject with Principals modeling groups and/or roles. Authorization will treat these accordingly.

RIGHT

jaas.config

grant Principal foo.Role "administrator" { 
    permission java.io.FilePermission "/etc/passwd", "read, write"; 
} 

grant Principal foo.Team "slamDunk" { 
    permission be.jcs.auth.DunkPermission "dunk"; 
}

JAAS_009: Use A PrincipalComparator To Structure Principals Hierarchically

A Principal implementation can in fact implement the interface PrincipalComparator which can be used to support role hierarchies.

RIGHT

Following sample grants user permissions to admin.

public class MyPrincipalComparator {
	public boolean implies(Subject subject) {
		// Verify hierarchy, eg admin is granted all user-permissions
	}
}

public class MyPrincipal extends MyPrincipalComparator implements Principal, Serializable {
	// ...
}

jaas.config

grant Principal MyPrincipal "user" {
    // ...
}

JAAS_010: Use A PriviledgedExceptionAction To Raise Checked Exceptions From Secured Code Fragments

A common PriviledgedAction cannot raise checked Exceptions (do not abuse the return Object to report an Exception). One should use a PriviledgedExceptionAction instead.

WRONG

public class MyPrivilegedAction implements PrivilegedAction { 
	public Object run() { 
		try { 
			// ... 
		} catch (CheckedException e) {
			throw new RuntimeException(e);
		}
	}
}

RIGHT

public class MyPrivilegedAction implements PrivilegedExceptionAction { 
	public Object run() throws Exception { 
		// ...
	}
}

JAAS_011: Use The doAsPriviledged Method Of A Subject Instead Of The doAs Method

Make sure execution of PrivilegedActions starts on a blank AccessControllerContext. Avoid to pass the currentThread's AccessControllerContext. Invoking Subject.doAsPrivileged is sufficient to force that a temporary AccessControllerContext is used to trace priviledges for a given PriviledgedAction.

RIGHT

public class MyPrivilegedAction implements PrivilegedAction { 
	public Object run() { 
		// ... 
	}
}

public class Foo {
	public static void main(final String[] args) {
		LoginContext foo = new LoginContext("Foo");
		foo.login();
		Subject subject = foo.getSubject();
		subject.doAsPriviledged(subject, new MyPriviledgedAction(), null);
	}
}

Site powered by a free Open Source Project / Non-profit License (more) of Confluence - the Enterprise wiki.
Learn more or evaluate Confluence for your organisation.
Hosted by JavaLobby
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.2.5 Build:#520 Jun 27, 2006) - Bug/feature request - Contact Administrators