This is my problem:
I have a web application that worked well until Saturday. But then it can not load my entitlements anymore.
Here is the piece of code in my shiro.ini file
entityRealm = com.cagecfi.shiro.EntityRealm
securityManager.authorizer = $entityRealm
authentif = com.cagecfi.Entities.Utilisateur
and the java class :
public class EntityRealm extends AuthorizingRealm{
protected UtilisateurFacadeLocal utifl;
protected ProfilRoleFacadeLocal prfl;
protected static Utilisateur utilisateur;
protected static Profil profil;
protected static List<ProfilRole> profilRoles;
public EntityRealm() throws NamingException {
System.out.println("enter entity realm");
this.setName("entityRealm");
CredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher("SHA-256");
this.setCredentialsMatcher(credentialsMatcher);
InitialContext context = new InitialContext();
this.utifl = (UtilisateurFacadeLocal) context.lookup("java:global/DOLEANCESAPPLI/UtilisateurFacade");
this.prfl = (ProfilRoleFacadeLocal) context.lookup("java:global/DOLEANCESAPPLI/ProfilRoleFacade");
System.out.println("out entity realm");
}
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
final UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
utilisateur = utifl.getOneBy("login", token.getUsername());
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo();
try {
if (utilisateur != null) {
simpleAuthenticationInfo = new SimpleAuthenticationInfo(utilisateur.getLogin(), utilisateur.getPassword(), getName());
} else {
simpleAuthenticationInfo = null;
throw new UnknownAccountException("Utilisateur inconnu");
}
} catch (Exception e) {
e.printStackTrace();
}
return simpleAuthenticationInfo;
}
#Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userId = (String) principals.fromRealm(this.getName()).iterator().next();
utilisateur = utifl.getOneBy("login", userId);
if (utilisateur != null) {
final SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
profilRoles = this.prfl.getBy("profil", utilisateur.getProfil());
final List<String> roles = new ArrayList<>();
profilRoles.stream().forEach((proRole) -> {
roles.add(proRole.getRole().getNom());
});
info.addRoles(roles);
return info;
} else {
return null;
}
}
public static Utilisateur getUser() {
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.isAuthenticated()) {
return utilisateur;
}
return null;
}
public static Subject getSubject() {
return SecurityUtils.getSubject();
}
#Override
public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
super.clearCachedAuthorizationInfo(principals);
}
}
n a bizarre way, shiro has been sending me this since Saturday.
Exception during lifecycle processing
java.lang.Exception: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.shiro.config.ConfigurationException: Unable to instantiate class [com.cagecfi.shiro.EntityRealm] for object named 'entityRealm'. Please ensure you've specified the fully qualified class name correctly.
To clarify just after a clean and build it began to send me this error.
I even recovered the previous backup of the project and still nothing.
Can someone help me and tell me where I missed something?
Thank you.
Related
Currently upgrading play framework to 2.7.* I'm getting an error response due to deprecation in the security authenticator class of HTTP.Context class
The application was on Play 2.6.* and auth was working as designed. If I roll back to 2.6.* the authentication works well. Essentially I'm hoping to return the auth token as a String.
#Override
public String getUsername(Http.Request ctx) {
Optional token = getTokenFromHeader(ctx);
if(token.isPresent()){
UserAccount userAccount = UserAccount.find.query().where().eq("authtoken",token.toString()).findOne();
if (userAccount != null){
//ctx.args.put("userAccount", userAccount);
//String resp = Optional.<String>ofNullable(null).orElse(orelesMethod());
String resp = Optional.<String>ofNullable(null).orElse(userAccount.authtoken);
return resp;
}
}
return null;
}
#Override
public Result onUnauthorized(Http.Request ctx) {
Logger.info("onUnauthorized");
ObjectNode result = Json.newObject();
result.put("error","Unauthorized, Please login");
return status(401,result);
}
private Optional getTokenFromHeader(Http.Request ctx) {
return ctx.header("X-AUTH-TOKEN");
}
}
Original Code is as below
public class Secured extends Security.Authenticator{
#Override
public String getUsername(Http.Context ctx) {
String token = getTokenFromHeader(ctx);
if(token != null){
UserAccount userAccount = UserAccount.find.query().where().eq("authtoken",token).findOne();
if (userAccount != null){
ctx.args.put("userAccount", userAccount);
return userAccount.authtoken;
}
}
return null;
}
#Override
public Result onUnauthorized(Http.Context ctx) {
Logger.info("onUnauthorized");
ObjectNode result = Json.newObject();
result.put("error","Unauthorized, Please login");
return status(401,result);
}
private String getTokenFromHeader(Http.Context ctx) {
String[] authTokenHeaderValues = ctx.request().headers().get("X-AUTH-TOKEN");
if ((authTokenHeaderValues != null) && (authTokenHeaderValues.length == 1) && (authTokenHeaderValues[0] != null)) {
return authTokenHeaderValues[0];
}
return null;
}
}
Error response
return type java.lang.String is not compatible with java.util.Optional<java.lang.String>
Play 2.7 has some changes in Security.Authenticator class. Now it has two methods named getUsername.
You override method with Request param, so you should return Optional not String.
Take a look on Authenticator code:
/**
* Handles authentication.
*/
public static class Authenticator extends Results {
#Deprecated
public String getUsername(Context ctx) {
return ctx.session().get("username");
}
// You override this method
public Optional<String> getUsername(Request req) {
return req.session().getOptional("username");
}
...
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I have a problem. Please take a look at these codes. When I click to login button first time it throws null pointer exception even I am typing correct username and password. But second time everything goes fine. How can I solve this issue?
I have attached OracleDBConnection and Login servlet. Null pointer exception happens in OracleDBConnection file.
Thanks for reading.
OracleDBConnection.java
public class OracleDBConnection {
private static volatile OracleDataSource instance = null;
private static final DBPropertyController DB_PROPERTY = new DBPropertyController();
private static final String URL = DB_PROPERTY.getProperty("url");
private static final String USERNAME = DB_PROPERTY.getProperty("username");
private static final String PASSWORD = DB_PROPERTY.getProperty("password");
private static final String PORT = DB_PROPERTY.getProperty("port");
private OracleDBConnection(){
}
private static void initialize() {
try {
instance = new OracleDataSource();
instance.setURL(URL);
instance.setUser(USERNAME);
instance.setPassword(PASSWORD);
instance.setPortNumber(Integer.parseInt(PORT));
} catch (SQLException ex) {
Logger.getLogger(OracleDBConnection.class.getName()).log(Level.ERROR, ex);
}
}
public static OracleDataSource getInstance() {
OracleDataSource ods = OracleDBConnection.instance;
if(ods == null) {
synchronized(OracleDataSource.class){
ods = OracleDBConnection.instance;
if(ods == null) {
initialize();
}
}
}
return ods;
}
}
Login.java
#WebServlet(name = "Login", urlPatterns = {"/login"})
public class Login extends HttpServlet {
private final LogController logger = new LogController();
private final JWTController jwt_controller = new JWTController();
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//processRequest(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
request.setCharacterEncoding("UTF-8");
LoginController login_controller = new LoginController();
HttpSession session = request.getSession(true);
String username = request.getParameter("username");
String password = request.getParameter("password");
int role = 0;
try {
role = Integer.parseInt(request.getParameter("userrole"));
} catch(NumberFormatException ex) {
Logger.getLogger(Login.class.getName()).log(Level.ERROR, null, ex);
role=0;
}
if(username!=null && password!=null && !username.equals("") && !password.equals("") && isRoleValid(role)){
if(login_controller.validateLogin(username, password, role)) {
// get manager object
Manager manager = login_controller.getManager(username, password, role);
long currentEpochTime = LocalDateTime.now().atZone(ZoneId.systemDefault()).toEpochSecond();
// set manager object to session
session.setAttribute("manager", manager);
//generate token
String token = jwt_controller.generateToken(username, MD5.generate(password), role);
// set token to cookie
Cookie cookie = new Cookie("token", token);
// add cookie to response
response.addCookie(cookie);
// check password expire date
if(manager.getPaswd_edate() > currentEpochTime) {
// signed in
response.getWriter().write("Signed in");
} else {
// expired
response.getWriter().write("Expired");
}
// add log
logger.addLog(username, "Signed in.", request.getRemoteHost(), request.getHeader("user-agent"));
} else {
response.getWriter().write("Error");
}
} else {
response.getWriter().write("Error");
}
}
private boolean isRoleValid(int role) {
return role==0 || role==1 || role==2 || role==3;
}
}
You haven't mentioned where is your NPE, but I guess it is because your OracleDBConnection.getInstance() returns null object first time it is called.
Change your lines
synchronized(OracleDataSource.class){
ods = OracleDBConnection.instance;
if(ods == null) {
initialize();
}
}
to
synchronized(OracleDataSource.class){
if(ods == null) {
initialize();
}
ods = OracleDBConnection.instance;
}
A NullPointerException occurs on the indicated line of my endpoint api method when called by the android client but not when called from the api explorer:
#ApiMethod(name = "publishReview", path = "publish-review", httpMethod = ApiMethod.HttpMethod.POST)
public Review publishReview(#Named("userId") final String id, ReviewForm reviewForm) {
Key<Profile> profileKey = Key.create(Profile.class, id);
final Key<Review> reviewKey = factory().allocateId(profileKey, Review.class);
final Long reviewId = reviewKey.getId();
Profile user = ofy().load().key(profileKey).now();
Review review = new Review(reviewId, id, reviewForm);
user.addToMyReviews(reviewId); // NULLPOINTER HERE
ofy().save().entities(review, user).now();
return review;
}
Here is addToMyReviews(Long reviewId):
public void addToMyReviews(final Long reviewId) {
if (!myReviews.contains(reviewId))
myReviews.add(reviewId);
}
Here is the android client side call of the endpoint method:
public static class PublishReview extends AsyncTask<Void, Void, String> {
private static MyApi myApiService = null;
private ReviewForm mReview;
private final String mUserId;
private Context mContext;
public PublishReview(final String userId, ReviewForm review, Context context) {
mReview = review;
mUserId = userId;
mContext = context;
}
#Override
protected String doInBackground(Void... params) {
if (myApiService == null) { // Only do this once
MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
// options for running against local devappserver
// - 10.0.2.2 is localhost's IP address in Android emulator
// - turn off compression when running against local devappserver
.setRootUrl("http://10.0.2.2:8080/_ah/api/")
.setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
#Override
public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
abstractGoogleClientRequest.setDisableGZipContent(true);
}
});
myApiService = builder.build();
}
try {
return myApiService.publishReview(mUserId, mReview).execute().getTitle();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(String title) {
Toast.makeText(mContext, title + " published", Toast.LENGTH_LONG).show();
}
}
The mUserId and mReview variables on the client side are not null when passed into the endpoint method as params.
How do I fix this error?
Based on this Jaspic Example I wrote the following validateRequest method for a ServerAuthModule:
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject,
Subject serviceSubject) throws AuthException {
boolean authenticated = false;
final HttpServletRequest request =
(HttpServletRequest) messageInfo.getRequestMessage();
final String token = request.getParameter("token");
TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal();
Callback[] callbacks = new Callback[] {
new CallerPrincipalCallback(clientSubject, (TokenPrincipal) null) };
if (principal != null) {
callbacks = new Callback[] {
new CallerPrincipalCallback(clientSubject, principal) };
authenticated = true;
} else {
if (token != null && token.length() == Constants.tokenLength) {
try {
principal = fetchUser(token);
} catch (final Exception e) {
throw (AuthException) new AuthException().initCause(e);
}
callbacks = new Callback[]
{
new CallerPrincipalCallback(clientSubject, principal),
new GroupPrincipalCallback(clientSubject,
new String[] { "aRole" })
};
messageInfo.getMap().put("javax.servlet.http.registerSession", "TRUE");
authenticated = true;
}
}
if (authenticated) {
try {
handler.handle(callbacks);
} catch (final Exception e) {
throw (AuthException) new AuthException().initCause(e);
}
return SUCCESS;
}
return AuthStatus.SEND_FAILURE;
}
This works as expected, for the first call of an ejb with #RolesAllowed("aRole") but for the next call this does not work at all. Wildfly denies it with this error message:
ERROR [org.jboss.as.ejb3.invocation] (default task-4) WFLYEJB0034: EJB Invocation
failed on component TestEJB for method public java.lang.String
com.jaspic.security.TestEJB.getPrincipalName():
javax.ejb.EJBAccessException: WFLYSEC0027: Invalid User
If I guess right, the error occures in:
org.jboss.as.security.service.SimpleSecurityManager line 367 of wilfly's source code, due to line 405, in which credential is checked, but seems to be null.
This seems equal in Wildfly 8/9/10CR (other versions not tested).
Again I'm not sure, if I'm doing it wrong, or if this is the same bug as
https://issues.jboss.org/browse/WFLY-4626 ? And is it a bug at all, or is it expected behavior?
This sounds like a bug to me as well, as the caller identity (caller / group Principals) appears to be retained in subsequent calls to the web, yet not to the EJB container. My own JASPIC classes (which function properly on GlassFish 4.1) fail for the same reason on WildFly 9.0.2.Final and 10.0.0.CR4 when used along with a plain Servlet and an SLSB, even with the latter marked #PermitAll.
As I'm myself unfamiliar with WildFly security internals I can not assist you in that respect. Unless you can get this patched, the sole SAM-level workaround I can think of for the time being would be to not use the javax.servlet.http.registerSession callback property that seemingly triggers the problem, but instead have the CallbackHandler register both the caller Principal and its groups on every validateRequest(...) invocation. If applicable to your use case, you may wish to attach that information to the HttpSession so as to speed up the process a bit; otherwise repeat from scratch. So, for example:
public class Sam implements ServerAuthModule {
// ...
#Override
public AuthStatus validateRequest(MessageInfo mi, Subject client, Subject service) throws AuthException {
boolean authenticated = false;
boolean attachAuthnInfoToSession = false;
final String callerSessionKey = "authn.caller";
final String groupsSessionKey = "authn.groups";
final HttpServletRequest req = (HttpServletRequest) mi.getRequestMessage();
TokenPrincipal tp = null;
String[] groups = null;
String token = null;
HttpSession hs = req.getSession(false);
if (hs != null) {
tp = (TokenPrincipal) hs.getAttribute(callerSessionKey);
groups = (String[]) hs.getAttribute(groupsSessionKey);
}
Callback[] callbacks = null;
if (tp != null) {
callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) };
authenticated = true;
}
else if (isValid(token = req.getParameter("token"))) {
tp = newTokenPrincipal(token);
groups = fetchGroups(tp);
callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) };
authenticated = true;
attachAuthnInfoToSession = true;
}
if (authenticated) {
try {
handler.handle(callbacks);
if (attachAuthnInfoToSession && ((hs = req.getSession(false)) != null)) {
hs.setAttribute(callerSessionKey, tp);
hs.setAttribute(groupsSessionKey, groups);
}
}
catch (IOException | UnsupportedCallbackException e) {
throw (AuthException) new AuthException().initCause(e);
}
return AuthStatus.SUCCESS;
}
return AuthStatus.SEND_FAILURE;
}
// ...
#Override
public void cleanSubject(MessageInfo mi, Subject subject) throws AuthException {
// ...
// just to be safe
HttpSession hs = ((HttpServletRequest) mi.getRequestMessage()).getSession(false);
if (hs != null) {
hs.invalidate();
}
}
private boolean isValid(String token) {
// whatever
return ((token != null) && (token.length() == 10));
}
private TokenPrincipal newTokenPrincipal(String token) {
// whatever
return new TokenPrincipal(token);
}
private String[] fetchGroups(TokenPrincipal tp) {
// whatever
return new String[] { "aRole" };
}
}
I tested the above on the aforementioned WildFly versions and in the aforementioned fashion (i.e. with a single Servlet referencing a single SLSB marked #DeclareRoles / method-level #RolesAllowed) and it seems to work as expected. Obviously I cannot guarantee that this approach will not fail in other unexpected ways.
See also:
[WFLY-4625]
[SECURITY-744]
[SECURITY-745]
I have to write some dao tests for project where I want to:
create DDL schema from database (MySQL);
create tables in another test database in memory (H2);
insеrt some data to database;
select the just inserted item;
check some data from this item.
This is my test:
public class BridgeDBTest {
private static String JDBC_DRIVER;
private static String JDBC_URL;
private static String USER;
private static String PSWD;
private static final Logger logger = LoggerFactory.getLogger(BridgeDBTest.class);
#BeforeGroups(groups = "bridgeDB")
public void init(){
try {
JDBC_DRIVER = org.h2.Driver.class.getName();
JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";
USER = "root";
PSWD = "";
new HibernateTestUtil().setDialect("org.hibernate.dialect.HSQLDialect")
.translateCreateDllToOutputStream(new FileOutputStream(new File("src/test/resources/createSchema.sql")));
RunScript.execute(JDBC_URL, USER, PSWD, "src/test/resources/createSchema.sql", Charset.forName("UTF8"), false);
insertDataset(readDataSet());
}
catch (Exception expt) {
expt.printStackTrace();
logger.error("!!!" + expt);
throw new RuntimeException(expt.getMessage());
}
}
#Test(groups = "bridgeDB")
public void getItem(){
BridgeDAOImpl dao = new BridgeDAOImpl();
dao.setSessionFactory(new HibernateTestUtil().getSessionFactory());
try {
Bridge bridge = dao.get(1L);
assert(bridge.getName().equals("TEST-CN-DEVBOX01"));
} catch (ServiceException e) {
e.printStackTrace();
}
}
#AfterGroups(groups = "bridgeDB")
public void dropTables(){
try {
new HibernateTestUtil().setDialect("org.hibernate.dialect.HSQLDialect")
.translateDropDllToOutputStream(new FileOutputStream(new File("src/test/resources/dropSchema.sql")));
}
catch (Exception expt) {
expt.printStackTrace();
logger.error("!!!" + expt);
throw new RuntimeException(expt.getMessage());
}
}
private IDataSet readDataSet() throws Exception{
return new FlatXmlDataSetBuilder().build(new File("src/test/resources/datasetForTest.xml"));
}
private void insertDataset(IDataSet dataSet) throws Exception{
IDatabaseTester databaseTester = new JdbcDatabaseTester(JDBC_DRIVER, JDBC_URL, USER, PSWD);
databaseTester.setSetUpOperation(DatabaseOperation.CLEAN_INSERT);
databaseTester.setDataSet(dataSet);
databaseTester.onSetup();
}
}
BridgeDAOImplused class HibernateUtilfrom src/main/..., but I need to use my class HibernateTestUtil from src/test/.... It's modified HibernateUtil fitted for my test (there I set parameters for Configuration class).
BridgeDAOImpl (See 5 line in try block):
public class BridgeDAOImpl extends GenericDAOImpl<Bridge, Long> implements BridgeDAO {
//...
public SearchResult<Bridge> list(int from, int limit, String filter, String order, Long authId) throws ServiceException {
SearchResult<Bridge> results = null;
Search search = new Search(Bridge.class);
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
search.setFirstResult(from);
search.setMaxResults(limit);
HibernateUtil.buildSearch(filter, order, search, aliases);
results = searchAndCount(search);
transaction.commit();
}
catch (Exception expt) {
logger.error("!!!", expt);
if (transaction != null) {
transaction.rollback();
}
throw new ServiceException(expt.getMessage());
}
finally {
// session.close();
}
return results;
}
//...
}
How I can test my dao without modifying it?