Hello, i am new and i have the same problem since a week.
At first I want to take, the default LoginModule:
default {
com.sun.enterprise.security.auth.login.ClientPasswordLoginModule required debug=false;
};
also i don't edit the "appclientlogin.conf"-file.
In the next Step i wrote a custom Realm:
package MyFileRealm;
import java.lang.*;
import java.util.*;
import java.util.logging.Logger ;
import java.util.logging.Level ;
import com.sun.logging.LogDomains;
import java.io.*;
import java.security.*;
import javax.security.auth.login.*;
import com.sun.enterprise.security.auth.realm.User;
import com.sun.enterprise.security.auth.realm.Realm;
import com.sun.enterprise.security.auth.realm.BadRealmException;
import com.sun.enterprise.security.auth.realm.NoSuchUserException;
import com.sun.enterprise.security.auth.realm.NoSuchRealmException;
import com.sun.enterprise.security.auth.realm.AuthenticationHandler;
import com.sun.enterprise.security.auth.realm.InvalidOperationException;
import com.sun.enterprise.server.*;
import com.sun.enterprise.security.RealmConfig;
import com.sun.enterprise.security.util.*;
import com.sun.enterprise.security.auth.realm.IASRealm;
import MyFileRealm.FileRealmUser;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
final public class FileRealm extends IASRealm
{
// Descriptive string of the authentication type of this realm.
public static final String AUTH_TYPE = "BASIC";
// These are property names which should be in auth-realm in server.xml
public static final String PARAM_KEYFILE="file2";
// Separators in keyfile (user;pwd-info;group[,group]*)
private static final String FIELD_SEP=";";
private static final String GROUP_SEP=",";
private static final String COMMENT="#";
// Valid non-alphanumeric/whitespace chars in user/group name
public static final String MISC_VALID_CHARS="_-.";
// Number of bytes of salt for SSHA
private static final int SALT_SIZE=8;
// Contains cache of keyfile data
private Map userTable; // user=>FileRealmUser
private Hashtable groupSizeMap; // maps of groups with value cardinality of group
private boolean constructed = false;
public FileRealm(String keyfile)
throws BadRealmException, NoSuchRealmException
{
File fp = new File(keyfile);
// if not existent, try to create
if (!fp.exists()) {
FileOutputStream fout = null;
try {
fout = new FileOutputStream(fp);
fout.write("\n".getBytes());
} catch (Exception e) {
String msg = sm.getString("filerealm.noaccess", e.toString());
throw new BadRealmException(msg);
} finally {
if (fout != null) {
try {
fout.close();
} catch(Exception ex) {
// ignore close exception
}
}
}
}
constructed = true;
Properties p = new Properties();
p.setProperty(PARAM_KEYFILE, keyfile);
p.setProperty(IASRealm.JAAS_CONTEXT_PARAM, "ignore");
this.init(p);
}
/**
* Constructor.
*
* <P>Do not use directly.
*/
public FileRealm()
{
}
protected void init(Properties props)
throws BadRealmException, NoSuchRealmException
{
String file = props.getProperty(PARAM_KEYFILE);
if (file == null) {
String msg = sm.getString("filerealm.nofile");
throw new BadRealmException(msg);
}
this.setProperty(PARAM_KEYFILE, file);
String jaasCtx = props.getProperty(IASRealm.JAAS_CONTEXT_PARAM);
if (jaasCtx == null) {
String msg = sm.getString("filerealm.nomodule");
throw new BadRealmException(msg);
}
this.setProperty(IASRealm.JAAS_CONTEXT_PARAM, jaasCtx);
_logger.fine("FileRealm : "+PARAM_KEYFILE+"="+file);
_logger.fine("FileRealm : "+IASRealm.JAAS_CONTEXT_PARAM+"="+
jaasCtx);
loadKeyFile();
}
public String getAuthType()
{
return AUTH_TYPE;
}
public Enumeration getUserNames()
throws BadRealmException
{
return (new Vector(userTable.keySet())).elements(); // ugh
}
public User getUser(String name)
throws NoSuchUserException
{
FileRealmUser u = (FileRealmUser)userTable.get(name);
if (u == null) {
String msg = sm.getString("filerealm.nouser", name);
throw new NoSuchUserException(msg);
}
return u;
}
public Enumeration getGroupNames()
throws BadRealmException
{
return groupSizeMap.keys();
}
public Enumeration getGroupNames(String username)
throws NoSuchUserException
{
FileRealmUser ud = (FileRealmUser)userTable.get(username);
if (ud == null) {
String msg = sm.getString("filerealm.nouser", username);
throw new NoSuchUserException(msg);
}
String [] groups = ud.getGroups();
Vector v = new Vector();
if (groups != null) {
for (int i = 0; i < groups.length; i++) {
v.add(groups[i]);
}
}
return v.elements();
}
public void refresh()
throws BadRealmException
{
_logger.fine("Reloading file realm data.");
FileRealm newRealm = new FileRealm();
try {
newRealm.init(getProperties());
Realm.updateInstance(newRealm, this.getName());
} catch (Exception e) {
throw new BadRealmException(e.toString());
}
}
public String [] authenticate(String user, String password)
{
FileRealmUser ud = (FileRealmUser)userTable.get(user);
if (ud == null) {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("No such user: [" + user + "]");
}
return null;
}
boolean ok = false;
try {
ok = SSHA.verify(ud.getSalt(), ud.getHash(), password.getBytes());
} catch (Exception e) {
_logger.fine("File authentication failed: "+e.toString());
return null;
}
if (!ok) {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("File authentication failed for: ["+user+"]");
}
return null;
}
return ud.getGroups();
}
private static boolean isValid(String s, boolean userName)
{
for (int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (!Character.isLetterOrDigit(c) &&
!Character.isWhitespace(c) &&
MISC_VALID_CHARS.indexOf(c) == -1) {
if (userName && (c == '@')){
continue;
}
return false;
}
}
return true;
}
public static void validateUserName(String name)
throws IASSecurityException
{
if (name == null || name.length() == 0) {
String msg = sm.getString("filerealm.noname");
throw new IASSecurityException(msg);
}
if (!isValid(name, true)) {
String msg = sm.getString("filerealm.badname", name);
throw new IASSecurityException(msg);
}
if (!name.equals(name.trim())) {
String msg = sm.getString("filerealm.badspaces", name);
throw new IASSecurityException(msg);
}
}
public static void validatePassword(String pwd)
throws IASSecurityException
{
if (pwd == null) {
String msg = sm.getString("filerealm.emptypwd");
throw new IASSecurityException(msg);
}
if (!pwd.equals(pwd.trim())) {
String msg = sm.getString("filerealm.badspacespwd");
throw new IASSecurityException(msg);
}
}
public static void validateGroupName(String group)
throws IASSecurityException
{
if (group == null || group.length() == 0) {
String msg = sm.getString("filerealm.nogroup");
throw new IASSecurityException(msg);
}
if (!isValid(group, false)) {
String msg = sm.getString("filerealm.badchars", group);
throw new IASSecurityException(msg);
}
if (!group.equals(group.trim())) {
String msg = sm.getString("filerealm.badspaces", group);
throw new IASSecurityException(msg);
}
}
public static void validateGroupList(String [] groupList)
throws IASSecurityException
{
if (groupList == null || groupList.length == 0) {
return; // empty list is ok
}
for (int i=0; i<groupList.length; i++) {
validateGroupName(groupList[i]);
}
}
public synchronized void addUser(String name, String password,
String [] groupList)
throws BadRealmException, IASSecurityException
{
validateUserName(name);
validatePassword(password);
validateGroupList(groupList);
if (userTable.containsKey(name)) {
String msg = sm.getString("filerealm.dupuser", name);
throw new BadRealmException(msg);
}
addGroupNames(groupList);
FileRealmUser ud = createNewUser(name, password, groupList);
userTable.put(name, ud);
}
public synchronized void removeUser(String name)
throws NoSuchUserException
{
if (!userTable.containsKey(name)) {
String msg = sm.getString("filerealm.nouser", name);
throw new NoSuchUserException(msg);
}
FileRealmUser oldUser = (FileRealmUser)userTable.get(name);
userTable.remove(name);
reduceGroups(oldUser.getGroups());
}
public synchronized void updateUser(String name, String password,
String [] groups)
throws NoSuchUserException, BadRealmException,
IASSecurityException
{
updateUser(name, name, password, groups);
}
public synchronized void updateUser(String name, String newName, String password,
String [] groups)
throws NoSuchUserException, BadRealmException,
IASSecurityException
{
// user to modify must exist first
validateUserName(name);
if (!userTable.containsKey(name)) {
String msg = sm.getString("filerealm.nouser", name);
throw new NoSuchUserException(msg);
}
// do general validation
validateUserName(newName);
validateGroupList(groups);
if (password != null) { // null here means re-use previous so is ok
validatePassword(password);
}
// can't duplicate unless modifying itself
if (!name.equals(newName) && userTable.containsKey(newName)) {
String msg = sm.getString("filerealm.dupuser", name);
throw new BadRealmException(msg);
}
FileRealmUser oldUser = (FileRealmUser)userTable.get(name);
assert (oldUser != null);
// create user using new name
FileRealmUser newUser = new FileRealmUser(newName);
// set groups as provided by parameter
changeGroups(oldUser.getGroups(), groups);
newUser.setGroups(groups);
// use old password if no new pwd given
if (password==null) {
newUser.setSalt(oldUser.getSalt());
newUser.setHash(oldUser.getHash());
} else {
setPassword(newUser, password);
}
userTable.remove(name);
userTable.put(newName, newUser);
}
public void writeKeyFile(String filename)
throws IOException
{
synchronized(FileRealm.class) {
FileOutputStream out = null;
try {
out = new FileOutputStream(filename);
Iterator names = userTable.keySet().iterator();
while (names.hasNext()) {
String name = (String )names.next();
FileRealmUser ud = (FileRealmUser)userTable.get(name);
String entry = encodeUser(name, ud);
out.write(entry.getBytes());
}
} catch (IOException e) {
throw e;
} catch (Exception e) {
String msg = sm.getString("filerealm.badwrite", e.toString());
throw new IOException(msg);
} finally {
if (out != null) {
out.close();
}
}
}
_logger.fine("Done writing "+filename);
}
private void addGroupNames(String [] groupList) {
if (groupList != null) {
for (int i=0; i < groupList.length; i++) {
Integer groupSize = (Integer )groupSizeMap.get(groupList[i]);
groupSizeMap.put(groupList[i],
(groupSize != null) ?
new Integer (groupSize.intValue() + 1): new Integer (1));
}
}
}
private void reduceGroups(String [] groupList) {
if (groupList != null) {
for (int i=0; i < groupList.length; i++) {
Integer groupSize = (Integer )groupSizeMap.get(groupList[i]);
if (groupSize != null) {
int gpSize = groupSize.intValue() - 1;
if (gpSize > 0) {
groupSizeMap.put(groupList[i], new Integer (gpSize));
} else {
groupSizeMap.remove(groupList[i]);
}
}
}
}
}
/**
* This method update the internal group list.
*/
private void changeGroups(String [] oldGroupList, String [] newGroupList) {
addGroupNames(newGroupList);
reduceGroups(oldGroupList);
}
/**
* Load keyfile from config and populate internal cache.
*
*/
private void loadKeyFile() throws BadRealmException
{
String file = this.getProperty(PARAM_KEYFILE);
_logger.fine("Reading file realm: "+file);
userTable = new Hashtable();
groupSizeMap = new Hashtable();
BufferedReader input = null;
try {
input = new BufferedReader(new FileReader(file));
while (input.ready()) {
String line = input.readLine();
if (!line.startsWith(COMMENT) &&
line.indexOf(FIELD_SEP) > 0) {
FileRealmUser ud = decodeUser(line, groupSizeMap);
userTable.put(ud.getName(), ud);
}
}
} catch (Exception e) {
_logger.log(Level.WARNING, "filerealm.readerror", e);
throw new BadRealmException(e.toString());
} finally {
if (input != null) {
try {
input.close();
} catch(Exception ex) {
}
}
}
}
private static String encodeUser(String name, FileRealmUser ud)
{
StringBuffer sb = new StringBuffer ();
String cryptPwd = null;
sb.append(name);
sb.append(FIELD_SEP);
String ssha = SSHA.encode(ud.getSalt(), ud.getHash());
sb.append(ssha);
sb.append(FIELD_SEP);
String [] groups = ud.getGroups();
if (groups != null) {
for (int grp = 0; grp < groups.length; grp++) {
if (grp > 0) {
sb.append(GROUP_SEP);
}
sb.append((String )groups[grp]);
}
}
sb.append("\n");
return sb.toString();
}
private static FileRealmUser decodeUser(String encodedLine,
Map newGroupSizeMap)
throws IASSecurityException
{
StringTokenizer st = new StringTokenizer(encodedLine, FIELD_SEP);
String user = null;
String pwdInfo = null;
String groupList = null;
try { // these must be present
user = st.nextToken();
pwdInfo = st.nextToken();
} catch (Exception e) {
String msg = sm.getString("filerealm.syntaxerror", encodedLine);
throw new IASSecurityException(msg);
}
if (st.hasMoreTokens()) { // groups are optional
groupList = st.nextToken();
}
byte[] hash = new byte[20];
byte[] salt = SSHA.decode(pwdInfo, hash);
FileRealmUser ud = new FileRealmUser(user);
ud.setHash(hash);
ud.setSalt(salt);
Vector membership = new Vector();
if (groupList != null) {
StringTokenizer gst = new StringTokenizer(groupList,
GROUP_SEP);
while (gst.hasMoreTokens()) {
String g = gst.nextToken();
membership.add(g);
Integer groupSize = (Integer )newGroupSizeMap.get(g);
newGroupSizeMap.put(g, (groupSize != null) ?
new Integer (groupSize.intValue() + 1) : new Integer (1));
}
}
ud.setGroups(membership);
return ud;
}
private static FileRealmUser createNewUser(String name, String pwd,
String [] groups)
throws IASSecurityException
{
FileRealmUser ud = new FileRealmUser(name);
if (groups == null) {
groups = new String [0];
}
ud.setGroups(groups);
setPassword(ud, pwd);
return ud;
}
private static void setPassword(FileRealmUser user, String pwd)
throws IASSecurityException
{
assert (user != null);
byte[] pwdBytes = pwd.getBytes();
SecureRandom rng=new SecureRandom();
byte[] salt=new byte[SALT_SIZE];
rng.nextBytes(salt);
user.setSalt(salt);
byte[] hash = SSHA.compute(salt, pwdBytes);
user.setHash(hash);
}
public static void main(String [] args)
{
if (args.length==0) {
help();
}
try {
if ("-c".equals(args[0])) {
String [] groups=new String [0];
if (args.length>3) {
groups=new String [args.length-3];
for (int i=3; i<args.length; i++) {
groups[i-3]=args[i];
}
}
FileRealmUser ud = createNewUser(args[1], args[2], groups);
String out=encodeUser(args[1], ud);
System.out.println(out);
FileRealmUser u=decodeUser(out, new Hashtable());
System.out.println("verifies: "+
SSHA.verify(u.getSalt(), u.getHash(),
args[2].getBytes()));
} else if ("-v".equals(args[0])) {
FileRealmUser u=decodeUser(args[2], new Hashtable());
System.out.println("user: "+u.getName());
System.out.println("verifies: "+
SSHA.verify(u.getSalt(), u.getHash(),
args[1].getBytes()));
}
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
private static void help()
{
System.out.println("FileRealm -c <name <pwd [group]*");
System.out.println("FileRealm -v <pwd `output of -c`");
System.exit(1);
}
}
thats the "FileRealm" form "com.sun.enterprise.security.auth.realm.file.FileRealm". I copied the file in a java-class. after the building i copied the *.jar in the lib-directory of my glassfish-server. Now i must restart my glassfish and take a edit in Security - Realm - new:
Name: file2
Classname: MyFileRealm.FileRealm
jaas-context: FileRealm
file: ${com.sun.aas.instanceRoot}/config/keyfile2 (this file exists)
Now I create a simple EEApplication.
here the client:
import fileauthserver.serverRemote;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import javax.security.auth.login.LoginException;
public class Main {
public static void main(String[] args) throws NamingException, LoginException {
InitialContext ctx = new InitialContext();
Object ref = ctx.lookup("fileauthserver");
serverRemote objekt = (serverRemote) PortableRemoteObject.narrow(ref,serverRemote.class);
System.err.println("\n\n" + objekt.konto() + "\n\n");
}}
and here the serverapp:
package fileauthserver;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
@Stateless(mappedName="fileauthserver")
public class serverBean implements serverRemote {
@RolesAllowed("USERS")
public String konto(){
return "Kontostand: 11 Euro";
}
}
and here the remote interace:
package fileauthserver;
import javax.ejb.Remote;
@Remote
public interface serverRemote {
String konto();
}
in the last step, i create a "glassfish deployment desc. - sun-application.xml":
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-application PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Java EE Application 5.0//EN" "
http://www.sun.com/software/appserver/dtds/sun-application_5_0-0.dtd">
<sun-application>
<realm>file2</realm>
<security-role-mapping>
<role-name>USERS</role-name>
<group-name>bank_users</group-name>
</security-role-mapping>
</sun-application>
Now a main question. when i start my application, the bean asks me for username and password, but when i press "ok" the following Exeption comes:
com.sun.enterprise.appclient.MainWithModuleSupport <init>
WARNUNG: ACC003: Ausnahmefehler bei Anwendung.
javax.naming.NamingException: ejb ref resolution error for remote business interfacefileauthserver.serverRemote [Root exception is java.rmi.AccessException: CORBA NO_PERMISSION 0 No; nested exception is:
org.omg.CORBA.NO_PERMISSION: ----------BEGIN server-side stack trace----------
org.omg.CORBA.NO_PERMISSION: vmcid: 0x0 minor code: 0 completed: No
and so on..
when my realm is: <realm>file</realm> it works:
"Kontostand: 11 Euro"
why i have no permisson, then i want to take the realm <realm>file2</realm>?
sorry for the bad english...
[Message sent by forum member 'capaelia' (capaelia)]
http://forums.java.net/jive/thread.jspa?messageID=336396