Search code examples
mavenjakarta-eejaaswildfly-9

WFLYJPA0059: javax.persistence.PersistenceContext injection target is invalid. Only setter methods are allowed: boolean secureConnect(String, String)


I'm trying to implement JAAS in my Java EE desktop application (maven project) and i'm using Wildfly9 server. But I got this problem:

Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: WFLYEE0041: Component class tn.esprit.jaas.EgovDriver for component EgovDriver has errors: 
WFLYJPA0059: javax.persistence.PersistenceContext injection target is invalid.  Only setter methods are allowed: boolean tn.esprit.jaas.EgovDriver.secureConnect(java.lang.String, java.lang.String)
    at org.jboss.as.ee.component.deployers.ModuleJndiBindingProcessor$1.handle(ModuleJndiBindingProcessor.java:158)
    at org.jboss.as.ee.component.ClassDescriptionTraversal.run(ClassDescriptionTraversal.java:54)
    at org.jboss.as.ee.component.deployers.ModuleJndiBindingProcessor.processClassConfigurations(ModuleJndiBindingProcessor.java:187)
    at org.jboss.as.ee.component.deployers.ModuleJndiBindingProcessor.deploy(ModuleJndiBindingProcessor.java:144)
    at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:156)
    ... 5 more

This is my JAAS code, I know that it exist many problems, please help me to fix it. CallbackHundler:

package tn.esprit.jaas;

import java.io.IOException;

import javax.ejb.Stateless;
import javax.persistence.PersistenceContext;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;

/**
 * Session Bean implementation class EgovCallbackHandler
 */

@Stateless
public class EgovCallbackHandler implements EgovCallbackHandlerRemote ,CallbackHandler {
@PersistenceContext(name="egovernment")
private static String[] details=null;
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

    System.out.println("EgovCallbackHandler");
    NameCallback nameCallback = (NameCallback) callbacks[0];
    System.out.println(nameCallback.getPrompt());
    nameCallback.setName(details[0]);
    PasswordCallback passwordCallback = (PasswordCallback) callbacks[1];
    System.out.println(passwordCallback.getPrompt());
    passwordCallback.setPassword(details[1].toCharArray());
}
@Override
public String[] enterDetailConnexion(String login, String password){
    details = new String[2];
    details[0]=login;
    details[1]=password;

    return details;
} 
}

LoginModule:

import java.io.IOException;
import java.util.Map;

import javax.ejb.Stateless;
import javax.persistence.PersistenceContext;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

import tn.esprit.domain.Agent;
import tn.esprit.services.AgentGestion;

/**
 * Session Bean implementation class EgovLoginModule
 */
@Stateless
public class EgovLoginModule implements EgovLoginModuleRemote,LoginModule {
    @PersistenceContext(name="egovernment")
    public static final String[][] TEST_USERS = {{"u1","p1"},{"u2","p2"}};
    private Subject subject = null;
    private CallbackHandler callbackHandler = null;
    private EgovPrincipal egovPrincipal = null;
    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
            Map<String, ?> options) {
        this.subject=subject;
        this.callbackHandler=callbackHandler;
        System.out.println("initialize");

    }

    @Override
    public boolean login() throws LoginException {
        boolean flag=false;
        Agent agent=null;
        AgentGestion ag;
        System.out.println("login");
        Callback[] callbacksArray =new Callback[2];
        callbacksArray[0]=new NameCallback("Username: ");
        callbacksArray[1]=new PasswordCallback("Password: ",false);
        try {
            callbackHandler.handle(callbacksArray);
            String name =((NameCallback) callbacksArray[0]).getName();
            String password = new String (((PasswordCallback) callbacksArray[1]).getPassword());
            agent = new Agent();
            ag = new AgentGestion();
            agent = ag.Authentification(name, password);
            if (agent.getLogin().equals(name) && agent.getPwd().equals(password)){
                egovPrincipal = new EgovPrincipal(name);
                System.out.println("log succeess......");
                flag = true;

            }

            if(flag==false) throw new FailedLoginException("log fail............");
        } catch (IOException | UnsupportedCallbackException e) {

            e.printStackTrace();
        }
        return flag;
    }

    @Override
    public boolean commit() throws LoginException {
        boolean flag = false;
        System.out.println("coomit");
        if(subject != null && !subject.getPrincipals().contains(egovPrincipal)){
            subject.getPrincipals().add(egovPrincipal);
            flag=true;
        }
        return flag;
    }

    @Override
    public boolean abort() throws LoginException {
        if(subject !=null && egovPrincipal != null && subject.getPrincipals().contains(egovPrincipal))
            subject.getPrincipals().remove(egovPrincipal);

        subject = null;
        egovPrincipal = null;
        System.out.println("abort");
        return true;
    }

    @Override
    public boolean logout() throws LoginException {
        subject.getPrincipals().remove(egovPrincipal);
        subject=null;
        System.out.println("logout");
        return true;
    }


}

Principal:

package tn.esprit.jaas;

import java.io.Serializable;
import java.security.Principal;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.PersistenceContext;



/**
 * Session Bean implementation class EgovPrincipal
 */
@Named
@RequestScoped
public class EgovPrincipal implements Principal, Serializable {
    @PersistenceContext(name="egovernment")
    private static final long serialVersionUID = 1L;
    @Inject
    private final String name;


     public EgovPrincipal(String name) {

        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object obj) {
        boolean flag = false;
        if(obj instanceof EgovPrincipal) 
            flag = name.equals(((EgovPrincipal)obj).getName());
        return flag;
    }


}

Driver:

package tn.esprit.jaas;

import javax.ejb.Stateless;
import javax.persistence.PersistenceContext;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import tn.esprit.jaas.EgovCallbackHandler;

/**
 * Session Bean implementation class EgovDriver
 */
@Stateless
public class EgovDriver implements EgovDriverRemote {

    @PersistenceContext(name="egovernment")
public boolean secureConnect(String login, String password){
    boolean flag = false;
        EgovCallbackHandler ech = new EgovCallbackHandler();
        System.setProperty("java.security.auth.login.config", "jaas.configFile");
        LoginContext loginContext=null;
        while (true){

            try {
                ech.enterDetailConnexion(login, password);
                loginContext = new LoginContext("EgovJaas", new EgovCallbackHandler());
                loginContext.login();
                return flag = true;
                //while (flag) flag = egovDriver.performedAction(loginContext);
            } catch (LoginException  e) {
                System.out.println("++++++++" +e.getMessage());
                return flag;
            }
        }

    }


}

Solution

  • It's not 100% clear what you're exactly trying to do. Does "Java EE desktop application" means you're trying to access remote EJBs from a client application?

    Regardless, your approach seem problematic and it's a bit hard where to start.

    But to start somewhere, you're using plain JAAS code here, but JAAS is not the universal standard you may think it is. Not every application server is using it all. When they do, specifically JBoss/WildFly here, they all do it totally differently.

    Specifically, you're doing this in the LoginModule

    public boolean commit() throws LoginException {
        boolean flag = false;
        if (subject != null && !subject.getPrincipals().contains(egovPrincipal)) {
            subject.getPrincipals().add(egovPrincipal);
            flag=true;
        }
    
        return flag;
    }
    

    By which I assume you think WildFly will somehow know that the egovPrincipal will become the user principal (e.g. the one returned by HttpServletRequest#getUserPrincipal). Unfortunately this is not strictly the case. As mentioned, every server has its own method here. In case of JBoss/WildFly it's the first principal that is not of type Group, or the single principal in the CallerPrincipal group.

    The next big problem is that you made all the JAAS artefacts EJB components and the Principal a scoped CDI bean. This will not work either. IFF a server is using its own flavour of JAAS at all (and remember not even all servers use it), then it's always used via plain classes (no EE component annotations). The entry point (bootstrap), is typically done via listing the LoginModule class in a server specific XML file. In case of JBoss/WildFly this is standalone.xml.

    Do note that for Java EE 8 we're trying to greatly simplify setting up and customising security. With that approach you can indeed use Java EE components (CDI) to implement the various artefacts. See the reference implementation Soteria, and specifically the examples.