Bom dia a todos! agradeceria muito uma força com um problema que estou tendo.
Tenho un projeto rodando no Wildfly 8, como sistema de login, estou usando JAAS com a implementação padrão. Devido a uma mudança no controle de login, me vi obrigado a customizar o JAAS através da sua interface LoginModule.
A redireção para a tela de login funciona de maravilha, assim como a redireção para a tela de erro quando o usuário não consegue logar. O único problema é quando o usuário informa login e senha validos, o usuário é setado na sessão mas o rol não esta sendo setado, sendo que o JAAS não permite o acesso ás paginas protegidas pelo JAAS.
Uma vez que o usuario consegue logar, faco as seguintes verificações:
User user = (User) request.getUserPrincipal(); //retorna o usuário certo
if(user!=null){
System.out.println(user.getName());
Set roles = user.getRoles();
for (Object object : roles) {
Role rol = (Role) object;
System.out.println(rol.getName()); //Retorna o rol certo (admin)
}
}
System.out.println(request.isUserInRole("admin")); // retorna false
Obrigado pela ajuda!!!
segue o código:
Classe User :
import java.io.Serializable;
import java.security.Principal;
import java.util.Set;
public class User implements Principal,Serializable{
private String name;
private Set roles;
public User(String name){
System.out.println("setando user "+name);
this.name = name;
}
public String getName() {
return name;
}
public Set getRoles() {
return roles;
}
public void setRoles(Set roles) {
if (this.roles == null)
this.roles = roles;
}
}
Classe Roles:
public class Role implements Principal,Serializable{
private String name;
public Role(String name){
System.out.println("setando role "+name);
this.name = name;
}
public String getName() {
return name;
}
}
Classe LoginModule:
import java.nio.Buffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.*;
import java.util.*;
import javax.naming.*;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.sql.DataSource;
public class LoginModule implements LoginModule {
private boolean commitSucceeded = false;
private boolean succeeded = false;
private User user;
private Set Roles = new HashSet();
protected Subject subject;
protected CallbackHandler callbackHandler;
protected Map sharedState;
private String dataSourceName;
private String sqlUser;
private String sqlRoles;
/*
* Login do usuário.
*/
protected String loginInformado;
/*
* Senha do usuário.
*/
protected String senhaInformado;
/*
O método initialize() é invocado sempre que uma nova autenticação é solicitada.
São passados como parametros o Subject, CallbackHandler, o mapa de objetos compartilhados
e o mapa de opções do login.config (arquivo de configuração do JAAS). O mais importante destes parametros para nós será o options,
pois nele receberemos os parametros de sql e datasource.
* */
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
Map<String, ?> options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
dataSourceName = "java:jboss/datasources/CacDb";
sqlUser = "SELECT senha as 'password' FROM SXML_USUARIO WHERE email = ?";
sqlRoles = "SELECT grupo , 'Roles' FROM SXML_USUARIO WHERE email = ?";
}
/*O método login() é invocado quando é enviado os dados (login e senha) de autenticação.*/
@Override
public boolean login() throws LoginException {
// recupera o login e senha informados no form
getUsernamePassword();
Connection conn = null;
try {
// obtem a conexão
try {
Context initContext = new InitialContext();
//Context envContext = (Context) initContext.lookup("java:/comp/env");
DataSource ds = (DataSource) initContext.lookup(dataSourceName);
conn = ds.getConnection();
} catch (NamingException e) {
succeeded = false;
throw new LoginException("Erro ao recuperar DataSource: " + e.getClass().getName() + ": " + e.getMessage());
} catch (SQLException e) {
succeeded = false;
throw new LoginException("Erro ao obter conexão: " + e.getClass().getName() + ": " + e.getMessage());
}catch (Exception e) {
e.printStackTrace();
}
// valida o usuario
validaUsuario(conn);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
// acidiona o usuario e roles no mapa de compartilhamento
for (Object object : Roles) {
Role rol = (Role) object;
System.out.println(rol.getName());
}
sharedState.put("javax.security.auth.principal", user);
sharedState.put("javax.security.auth.roles", Roles);
return true;
}
/*O método commit() é invocado quando o login() obtém sucesso.*/
@Override
public boolean commit() throws LoginException {
// adiciona o usuario no principals
if (user != null && !subject.getPrincipals().contains(user)) {
subject.getPrincipals().add(user);
}
// adiciona as roles no principals
if (roles != null) {
Iterator it = roles.iterator();
while (it.hasNext()) {
Role role = (Role) it.next();
if (!subject.getPrincipals().contains(role)) {
subject.getPrincipals().add(role);
}
}
}
System.out.println(subject.toString());
commitSucceeded = true;
return true;
}
/*O método abort() é invocado quando o login() não obtém sucesso.*/
@Override
public boolean abort() throws LoginException {
if (!succeeded) {
return false;
} else if (succeeded && !commitSucceeded) {
succeeded = false;
} else {
succeeded = false;
logout();
}
this.subject = null;
this.callbackHandler = null;
this.sharedState = null;
this.Roles = new HashSet();
return succeeded;
}
/*O método logout() é invocado quando o usuário desloga da aplicação.*/
@Override
public boolean logout() throws LoginException {
// remove o usuario e as roles do principals
subject.getPrincipals().removeAll(Roles);
subject.getPrincipals().remove(user);
return true;
}
private void validaUsuario(Connection conn) throws LoginException {
String senhaBanco = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
statement = conn.prepareStatement(sqlUser);
statement.setString(1, loginInformado);
rs = statement.executeQuery();
if (rs.next()) {
senhaBanco = rs.getString(1);
} else {
succeeded = false;
throw new LoginException("Usuário não localizado.");
}
} catch (SQLException e) {
succeeded = false;
throw new LoginException("Erro ao abrir sessão: "
+ e.getClass().getName() + ": " + e.getMessage());
} finally {
try {
if (rs != null)
rs.close();
if (statement != null)
statement.close();
} catch (Exception e) {
}
}
if (stringToMD5(senhaInformado).equals(senhaBanco)) {
user = new User(loginInformado);
recuperaRoles(conn);
user.setRoles(Roles);
return;
} else {
throw new LoginException("Senha Inválida.");
}
}
private String stringToMD5(String senhaInformada) {
String MD5 = null;
try {
MessageDigest encripter = MessageDigest.getInstance("MD5");
encripter.update(senhaInformada.getBytes());
byte[] senhaEncriptada = encripter.digest();
StringBuffer buffer = new StringBuffer();
for (byte b : senhaEncriptada) {
buffer.append(String.format("%02x", b & 0xff));
}
MD5 = buffer.toString();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
return MD5;
}
private void recuperaRoles(Connection conn) throws LoginException {
PreparedStatement statement = null;
ResultSet rs = null;
try {
statement = conn.prepareStatement(sqlRoles);
statement.setString(1, loginInformado);
rs = statement.executeQuery();
while (rs.next()) {
System.out.println(rs.getString(1));
Roles.add(new Role(rs.getString(1)));
}
//roles.add(new Role("LOGADO"));
} catch (SQLException e) {
succeeded = false;
throw new LoginException("Erro ao recuperar roles: " + e.getClass().getName() + ": " + e.getMessage());
} finally {
try {
if (rs != null)
rs.close();
if (statement != null)
statement.close();
} catch (Exception e) {
}
}
}
private void getUsernamePassword() throws LoginException {
if (callbackHandler == null)
throw new LoginException("Error: no CallbackHandler available to garner authentication information from the user");
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("Login");
callbacks[1] = new PasswordCallback("Senha", false);
try {
callbackHandler.handle(callbacks);
loginInformado = ((NameCallback) callbacks[0]).getName();
char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
senhaInformado = new String(tmpPassword);
((PasswordCallback) callbacks[1]).clearPassword();
} catch (java.io.IOException ioe) {
throw new LoginException(ioe.toString());
} catch (UnsupportedCallbackException uce) {
throw new LoginException("Error: " + uce.getCallback().toString() + " not available to garner authentication information from the user");
}
}
}
web.xml:
<!-- Somente admin -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Users and admins</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<!-- Somente logados -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Users and admins</web-resource-name>
<url-pattern>/private/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<!-- Validation By Form -->
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/public/login/</form-login-page>
<form-error-page>/public/login/?error=true</form-error-page>
</form-login-config>
</login-config>
<!-- Allowed Roles -->
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>user</role-name>
</security-role>
jboss-web:
<jboss-web>
<security-domain>tiss-domain</security-domain>
<context-root>/tiss</context-root>
</jboss-web>
standalone.xml:
<security-domain name="tiss-domain" cache-type="default">
<authentication>
<login-module code="br.org.cac.tiss.login.LoginModule" flag="required">
</login-module>
</authentication>
</security-domain>