I have a login servlet that processes post request with username and password parameters, and does something like this:
Instant pageGenStart = Instant.now();
String username = req.getParameter("username");
String password = req.getParameter("password");
resp.setContentType("text/html;charset=utf-8");
User user = null;
try {
user = userService.getByUsername(username);
} catch (SQLException e) {
e.printStackTrace();
}
if (user == null && !password.equals("")) {
try {
user = new User(username, password);
user.setId(userService.addNewUser(username, password));
charactersService.addNewCharacter(user);
sessionsService.add(req.getSession().getId(), user.getId());
} catch (SQLException e) {
e.printStackTrace();
}
resp.setContentType("text/html;charset=utf-8");
resp.setStatus(HttpServletResponse.SC_OK);
Duration time = Duration.between(pageGenStart, Instant.now());
resp.sendRedirect("/main");
}
If user is not found in db, create new user and redirect him to main page. Normally i would just put this "time" variable into page, but i redirect my response to other servlet where doGet method is called. How do i let other servlet know how long login servlet took to proccess post request?
You can pass value from one servlet to another in many ways like :
Storing values in session ( You have to take care of session management)
Creating class having static ConcurrentHashMap and storing time gap per user session and fetching it using session ID. (same problem need to take care when to clear cache).
Use already defined lib ( best option as you need not to worry about session management and cache clear).
I perfer EH-cache for these kind of perposes you can see a good example from the Link.
Related
We've migrated from adal4j to msal4j in our java web applications.
All works well but the big difference is that when the user is already logged (maybe in other applications but same browser session) we always see the "select user" page and the user is not logged automatically and redirected to redirect uri as before with adal4j.
This is how we redirect to autentication page:
private static void redirectToAuthorizationEndpoint(IdentityContextAdapter contextAdapter) throws IOException {
final IdentityContextData context = contextAdapter.getContext();
final String state = UUID.randomUUID().toString();
final String nonce = UUID.randomUUID().toString();
context.setStateAndNonce(state, nonce);
contextAdapter.setContext(context);
final ConfidentialClientApplication client = getConfidentialClientInstance();
AuthorizationRequestUrlParameters parameters = AuthorizationRequestUrlParameters
.builder(props.getProperty("aad.redirectURI"), Collections.singleton(props.getProperty("aad.scopes"))).responseMode(ResponseMode.QUERY)
.prompt(Prompt.SELECT_ACCOUNT).state(state).nonce(nonce).build();
final String authorizeUrl = client.getAuthorizationRequestUrl(parameters).toString();
contextAdapter.redirectUser(authorizeUrl);
}
I've tried to remove .prompt(Prompt.SELECT_ACCOUNT)
but I receive an error
Any ideas?
• You might be getting the option for selecting the user account after switching to MSAL4J in your browser even after the SSO is enabled because either clearing the token cache is enabled in your code or MsalInteractionRequiredException option is thrown and specified accordingly due to which the application asks for a token interactively.
Thus, please check which accounts information is stored in the cache as below: -
ConfidentialClientApplication pca = new ConfidentialClientApplication.Builder(
labResponse.getAppId()).
authority(TestConstants.ORGANIZATIONS_AUTHORITY).
build();
Set<IAccount> accounts = pca.getAccounts().join(); ’
Then, from the above information, if you want to remove the accounts whose prompts you don’t want to see during the user account selection such that the default account should get selected and signed in automatically, execute the below code by modifying the required information: -
Set<IAccount> accounts = pca.getAccounts().join();
IAccount accountToBeRemoved = accounts.stream().filter(
x -> x.username().equalsIgnoreCase(
UPN_OF_USER_TO_BE_REMOVED)).findFirst().orElse(null);
pca.removeAccount(accountToBeRemoved).join();
• And for the MsalInteractiveRequiredException class in the code, kindly refer to the below official documentation link for the AcquireTokenSilently and other reasons responsible for the behaviour. Also, refer to the sample code given below for your reference regarding the same: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-error-handling-java#msalinteractionrequiredexception
IAuthenticationResult result;
try {
ConfidentialClientApplication application =
ConfidentialClientApplication
.builder("clientId")
.b2cAuthority("authority")
.build();
SilentParameters parameters = SilentParameters
.builder(Collections.singleton("scope"))
.build();
result = application.acquireTokenSilently(parameters).join();
}
catch (Exception ex){
if(ex instanceof MsalInteractionRequiredException){
// AcquireToken by either AuthorizationCodeParameters or DeviceCodeParameters
} else{
// Log and handle exception accordingly
}
}
Given that,
I have a
USER_ACTIVITY_LOG table
that contains
USER_ID, SESSION_ID, ACTIVITY_CODE(Login/LogOut/TimeOut) &
ACTIVITY_TIME columns
in that. It updates all activities performed on the application in the table on basis of UserId & SessionId.
Problem Statement :
I want to restrict logins to maximum 2 users with the same credentials on my application.
Say at a time 2 users are logged into the application with the same credentials (eg: admin/admin) and now 3rd user is trying to log into application with the same credentials. In such case the oldest logged in user session should be invalidated.
I have to query USER_ACTIVITY_LOG table on every user login and check number of users logged in with the same userId and are not logged out.
If I get count of 2 users that are still logged in, I simply want to invalidate the session of the oldest user on basis of just SESSION_ID.
Is that possible ?
My project is on Java 8, Jboss 6.4, J2EE, Struts 2 & Oracle.
This is the fix I found out and I am using it as of now. No matter it will impact the performance a bit.
public void expireSessionWithId(String sessionID)
{
try {
MBeanServer server = java.lang.management.ManagementFactory.getPlatformMBeanServer();
ObjectName objectName=new ObjectName("jboss.web:type=Manager,path=/test,host=default-host");
// declare signature of the parameter
String[] sig = { "java.lang.String"};
// declare parameter
Object[] opArgs1 = { sessionID };
// call the method
String value = (String) server.invoke(objectName, "expireSession",
opArgs1, sig);
System.out.println(value);
} catch (MalformedObjectNameException e) {
//handle the exception
} catch (InstanceNotFoundException e) {
//handle the exception
} catch (ReflectionException e) {
//handle the exception
} catch (MBeanException e) {
//handle the exception
}
}
I am testing a new functionality in my web app where i'm allowing the user to remain signed in even after the browing session expires. In order to achieve this, i have a "Keep me logged in" checkbox on my login page. Upon successful login, a cookie is created containing the userID and the login process continues normally. The first thing the first method in my main controller does is check for the presence of that cookie, read the userId in it, set the User object in the session correctly and bypass the login process, going directly to the home page. When the user signs out, the cookie is recreated with an expiration of 0 which means it's automatically deleted.
My Spring sessions last 30 minutes currently. I have successfully tested everything but i'm trying to replicate the Spring session expiring, which gets rid of the User object in memory and would normally force the user to login. In order to replicate it, i am deleting the JSESSIONID cookie from Chrome. When i do that, the HttpServletRequest object (which I am checking cookies on) is null.
Here is the first code that runs in my main controller :
#RequestMapping(value = {"/"}, method = RequestMethod.GET)
public String home(ModelMap model, HttpServletRequest request)
{
if (session.getAttribute("loggedInUser") != null)
{
return "home";
}
else
{
String userId = null;
for (Cookie cookie : request.getCookies())
{
if (cookie.getName().compareTo("MDHISStaySignedIn") == 0)
{
userId = cookie.getValue();
break;
}
}
if (userId != null)
{
session.setAttribute("loggedInUser", userService.findByUserId(userId));
return "redirect:/";
}
else
{
model.addAttribute("login", new Login());
model.addAttribute("register", new Register());
model.addAttribute("registering", false);
return "login";
}
}
}
Is it normal that my request object is null when deleting this cookie? Am i not correctly replicating the Spring session timing out by deleting it? This NullPointerException only happens when deleting this cookie and upon first running the web app, the controller does not thrown the exception when the cookie is created by the first run. Should i somehow be checking for this null value and redirecting the controller back to this method if it is?
Thanks!
The solution is to add the following method parameter :
#CookieValue(value = "MDHISStaySignedIn", defaultValue = "notFound") String cookie
This will assign the content of the cookie to the value if it's present and assign "notFound" if it is not. This way one can access cookies when the request object is null!
I'm making a queue management system. I've hit on stump here. I'm letting the customer/user select their desired service whose token they want to get, but the thing is each time the servlet is called it re-initializes the service-option objects and the token number for that chosen services goes back to 1. How can I store the token count so that it doesn't goes back to 1 again.
public class XmlServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String Service_Option = request.getParameter("Service_Option");
out.println("You selected Service is: "+ Service_Option);
Customer_Console cc1 = new Customer_Console();
Customer_Console cc2 = new Customer_Console();
Customer_Console cc3 = new Customer_Console();
if(Service_Option.equals("Cash Withdrawal"))
{
cc1.setConsole(1,Service_Option);
Database_Manager.Insert(cc1);
}
else if(Service_Option.equals("Account Service"))
{
cc2.setConsole(2,Service_Option);
Database_Manager.Insert(cc2);
}
else
{
cc3.setConsole(3,Service_Option);
Database_Manager.Insert(cc3);
}
}
}
The Console class contains
private int serviceNum;
private String Service_Option;
private Token token;
and the setConsole method is
public void setConsole(int sNum,String sName)
{
serviceNum = sNum;
Service_Option = sName;
token.incrementToken();
}
UPDATE
I'm having problems with dealing the session for more then 1 customer consoles
HttpSession session = request.getSession(false);
if(session == null)
{
session = request.getSession(true);
Integer count = 0;
session.setAttribute("tokenCount",count);
}
if(Service_Option.equals("Cash Withdrawal"))
{
Integer count = (int)session.getAttribute("tokenCount");
count = new Integer(count.intValue() + 1);
cc1.setToken(count);
Database_Manager.Insert(cc1);
session.setAttribute("tokenCount",count);
}
Also how can I reset the session that every time I restart tomcat I get started with the token number 1.
If I'm supposed to use only one session for all three consoles then how can I do that?
I tried with placing the console objects
if(session == null)
{
session = request.getSession(true);
session.setAttribute("cc1", cc1);
}
if(Service_Option.equals("Cash Withdrawal"))
{
cc1.issueToken();
session.setAttribute("cc1", cc1);
cc1 = (Customer_Console)session.getAttribute("cc1");
Database_Manager.Insert(cc1);
}
But still it doesn't save the increments, again reinitializes the token, why is that?
Store Your service-option Object in session Scope So every time your servlet it called you can access the Object using
HttpSession session = request.getSession();
Console service-option=null;
service-option=(Console)session.getAttribute("console");
if(service-option==null){
service-option=new Console();
}
// After doing your work(setting some variables etc)of Console Class Object
// you can set that Object in Session Like this
session.setAttribute("console", service-option); // here "console" is key
In this way it is reinitialized only for the first time
As Java Docs Says
void setAttribute(String name,Object value)
Binds an object to this session, using the name specified. If an
object of the same name is already bound to the session, the object is
replaced.
Update
A HttpSession is created when calling request.getSession() and it get destroyed/invalidated when you call session.invalidate() or session timeout occurs .
Now coming to
Also how can I reset the session that every time I restart tomcat I
get started with the token number 1. If I'm supposed to use only one
session for all three consoles then how can I do that?
It will automatically get restarted but there will be no token number exist into it because it is fresh , if you need to access token number from your entire application then i suggest you to use Servlet Context
An object of ServletContext is created by the web container at time of
deploying the project.This object can be used to get configuration
information from web.xml file. There is only one ServletContext object
per web application.
If any information is shared to many servlet, it is better to provide
it from the web.xml file using the element.
Now your another confusion
I'm having problems with dealing the session for more then 1 customer
consoles
Please read Session Management in Java . As this topic is too broad so i have given you the link to read it yourself
I am new to this forum. I have a doubt about JSP/servlet in my application
I have developed an application in which user may search some data based on some criteria and he will get data from database(through Hibernate to servlet and to JSP). When some data is displayed on screen based on search he/she may try to copy the URL and forward to anyone or If he try to open in different browser it is showing an empty page.
eg: if i try to paste the link given bellow it is showing blank page
example link
but i need to display the data how this can be achieved.
Edited: After clicking on job search in menu bar as mentioned in comments the page will redirect to a servlet
if(action.equals("searchjob")){
String requireskills=request.getParameter("txt_requireSkills");
String location=request.getParameter("txt_locationName");
session.setAttribute("location",location);
String minexp1=request.getParameter("dd_minimum");
String maxexp1=request.getParameter("dd_maximum");
jobsearchDAO = new JobSearchDAOImpl();
List<JobPostInfo> data=jobsearchDAO.jobsearchlist(requireskills,location,minexp1,maxexp1);
if(data!=null && data.size()!=0){
//save data
if(!(session.getAttribute("LoginObject")==null)){
JobSeeker jobSeeker=(JobSeeker)session.getAttribute("LoginObject");
JobSearchCriteria jobsearchcriteria= new JobSearchCriteria();
jobsearchDAO=new JobSearchDAOImpl();
jobsearchcriteria.setKeyWords(requireskills);
jobsearchcriteria.setLocation(location);
JobSeeker jobseeker=(JobSeeker)session.getAttribute("jobseeker");
//
// jobsearchcriteria.setJobSeeker(jobseeker.getJobSeekerSn());
jobsearchcriteria.setJscTs(new Date());
int value=jobsearchDAO.savesearch(jobsearchcriteria);
System.out.println("savesearch value------>"+value);
}
session.setAttribute("jobsearchlist", data);
// session.setAttribute("success","Search Criteria is saved to database.");
response.sendRedirect("jobsearchresult.jsp");
}else
{
session.setAttribute("error","No Records found");
response.sendRedirect("jobsearch.jsp");
}
}
This is the code in DAOIMPL
public List<JobPostInfo> jobsearchlist(String requireskills,String location,String minexp1,String maxexp1) throws Exception{
long minexp;
long maxexp;
try{
session =getSession();
//Criteria Query
Criteria query=session.createCriteria(JobPostInfo.class,"jpost");
// if(minexp1.equals("0") && (maxexp1.equals("") || maxexp1==null)){
if((minexp1.equals("-1") || minexp1=="-1") && maxexp1==null){
}
else if(minexp1.equals("0")){
minexp=Long.parseLong(minexp1);
long min=1;
query.add(Restrictions.lt("jpost.experienceMin",min));
}else if(!(minexp1.equals("") || minexp1==null) && maxexp1.equals("-1")) {
minexp=Long.parseLong(minexp1);
query.add(Restrictions.ge("jpost.experienceMin",minexp));
}else if(!(minexp1==null && maxexp1==null)){
minexp=Long.parseLong(minexp1);
maxexp=Long.parseLong(maxexp1);
query.add(Restrictions.and(Restrictions.ge("jpost.experienceMin",minexp),Restrictions.le("jpost.experienceMax",maxexp)));
}
//For Location
if(!(location==null|| location.equals(""))){
query.createAlias("jpost.location","location");
query.add(Restrictions.like("location.locationName",location).ignoreCase());
}
//For Keyword
if(!(requireskills==null || requireskills.equals(""))){
query.add(Restrictions.like("jpost.requiredSkills","%"+requireskills+"%").ignoreCase());
}//requireskills
List<JobPostInfo> list = query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
if(list.size()==0){
return null;
}else{
return list;
}
}catch(HibernateException e){
e.printStackTrace();
}finally {
close(session);
}
return null;
}
I solved my problem. It's a very basic mistake and I hope this will help others:
response.sendRedirect("jobsearchresult.jsp") is replaced by request.getRequestDispatcher("studentinformation.jsp").forward(request, response)
or include-method. The second thing is, the session is created and initialized with the servlet. When I copy the link in a different browser, a certain block of the servlet will be executed. Example:
action.equals("searchjob")
So at the time the session is not available yet, I initialize it in every block like separating declaration and initialization.