I hope you guys will be able to help me understand the case in servlet method doGet.
for example, we have a User class with name and the last name, of course, getters and setters are set. Additional pieces of information are in comments in the code. The question is, what is the purpose of SetAttribute in this case? Should I use it? I see no difference when its on and off. Thank you in advance for your prompt response.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//here I initiate servlet to create a session yes?
HttpSession session = request.getSession(true);
// here im getting atribiute which is goinna be null now:
User user = (User) session.getAttribute("user");
//now in case of null i want to create object which can have null atributes like name and lastname:
if(user == null) {
user = createUser(request);
//here is my problem, i dont know what is it for? I already get atrributes, why would i want to set object again? to what?
session.setAttribute("user", user);
}
returnInfo(response,user);
}
protected User createUser(HttpServletRequest request) {
User user = new User();
String name = request.getParameter("name");
String lastname = request.getParameter("lastname");
user.setName(name);
user.setSurname(lastname);
return user;
}
protected void returnInfo(HttpServletResponse response,User user) throws IOException {
PrintWriter write = response.getWriter();
write.println("<html>");
write.println("<body>");
write.println("<div>");
if(user.getName() == null && user.getSurname() == null) {
write.println("no person was added");
}
else{
write.println("person is" + " " + user.getName() + " " + user.getSurname());
}
write.println("</div>");
write.println("</body>");
write.println("</html>");
}
You have just created a new user. It must be added to the session otherwise your user attribute will always be null.
Related
I have two users: A and B, if user A login first, user B cant login util user A logout. Each user require three login info: storeId, storePassword, userPassword.
If user B same storeId with user A, do not allow login
If user B different storeId with user A, allow login
I use ServletContext to hold users logged, and when logged user click logout, I will remove that user from ServletContext. But I cant hanle when user close brower intead of click logout. I think this is not a good idea
Here is my code
#Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
//redirectStrategy.sendRedirect(request, response, "/login");
// do whatever you want
ServletContext context = request.getSession().getServletContext();
Object _auths = context.getAttribute("_authentications");
if(_auths != null) {
List<String> auths = (List<String>) _auths;
auths.remove(authentication.getName());
if(auths.size() == 0) {
auths = new ArrayList<String>();
}
context.setAttribute("_authentications", auths);
}
super.onLogoutSuccess(request, response, authentication);
}
does anyone give me a good solution?
Thank you
i have solved my problem, i use SessionRegistry in AuthencationProvide intead of ServletContext
#Autowired
#Qualifier("sessionRegistry")
private SessionRegistry sessionRegistry;
List<Object> principals = sessionRegistry.getAllPrincipals();
for (Object principal: principals) {
String[] auths = principal.toString().split(StringPool.DASH);
if(auths.length == 4 && auths[1].equals(storeId)) {
throw new BadCredentialsException(auths[0]+StringPool.DASH+auths[1]);
}
}
this code work well when session time out, user close brower. And i dont need any js source code to handle
You can use the js below to remove user from servletContext on window close:
<script type="text/javascript">
window.onbeforeunload = logout;
function logout(){
// Make an ajax call to remove user from ServletContext
alert("Window close is being called");
return false;
}
</script>
I wrote a simple servlet, in the doPost I got the user name and the password from a jspand authenticated the user by sending the password entered by the user to the data base(mysql). I got the data correctly and I am redirecting the user to another jsp page called welcome.jsp.
my question is , I wrote this method public String getUser(){return userNmae;}; I put it outside of the dopost method, however it is returning null. I have declared the variable userNmae as a class variable and when I debug , the variable contains a value in the dopost method , but it is null outside of the dopost method.why it is null outside of the dopost method?
I am calling getUser() method in the welcome.jsp page.
here is my code
public class UIclass extends HttpServlet {
public UIclass() { };
private String passWord = null;
private String userNmae = null;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("userName");
String password = request.getParameter("password");
Connection connection = null;
try {
connection = Connections.getConnection();
java.sql.PreparedStatement statement = connection.prepareStatement("SELECT PASSWORD,USERNAME FROM LOGIN where username =?");
statement.setString(1, name);
ResultSet resultset = statement.executeQuery();
while (resultset.next()) {
passWord = resultset.getString("PASSWORD");
userNmae = resultset.getString("USERNAME");
}
} catch (Exception e) {
// TODO: handle exception
} finally {
if (connection != null)
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
};
}
if (passWord.equalsIgnoreCase(password)) {
RequestDispatcher rd = request.getRequestDispatcher("welcome.jsp");
rd.forward(request, response);
}
}
public String getUser() {
return userNmae;
}
}
I'll answer by giving you a simpler example of what your code is actually doing:
Bottle bottle1 = new Bottle();
bottle1.setMessage("Hi there");
Bottle bottle2 = new Bottle();
System.out.println(bottle2.getMessage());
What would you expect this program to display? I would expect null, because you set a message on bottle1, and read the message from bottle2. These are two different bottles. When you put a message in a bottle, the message is in that bottle, not in the other bottles.
Your code does the same thing.
The servlet container creates an instance (unique) of UIclass. This is equivalent to creating the first bottle in my example.
The servlet is invoked when you send an HTTP request. It sets the user attribute in the servlet. This is equivalent to bottle1.setMessage("Hi there") in my example.
The container executes your JSP, which contains the code
<jsp:useBean id="uiclass" class="com.servlet.UIclass" scope="request">
This creates a new UIClass instance. It is equivalent to creating the second bottle in my example.
The JSP calls uiclass.getUser(). This is equivalent to getting the message from the second bottle in my example.
There are many, many things wrong in your code:
You shouldn't use scriptlets, and jsp:useBean tags
You should never create instances of servlets by yourself. A servlet is meant to be instanciated and called by the container.
You should realize that a unique servlet instance is called to serve, concurrently, all the requests of all the users to this servlet URL. Storing user-specific data in servlet attributes is thus really wrong
You probably want the user name to be available for all the subsequent requests of this user. That's what the HTTP session is for. You should store the user as an attribute of the HTTP session: request.getSession().setAttribute("userName", userName)
The JSP should use the JSP EL and the JSTL to access beans stored in the request or the session by the servlet:
<c:out value="${userName}"/>
Given this doGet implementation:
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (request.getParameterMap().isEmpty()) {
// DAO initialized in init() method
Collection<User> users = resource.getUsers();
if (users != null){
HttpSession session = request.getSession();
session.setAttribute("users", users);
}
request.getRequestDispatcher("/WEB-INF/users/index.jsp").forward(request, response);
}
else {
String name = request.getParameter("name");
// DAO initialized in init() method
User user = resource.getUser(name);
if (user == null){
request.setAttribute("message", "Unknown user: " + name);
request.getRequestDispatcher("/WEB-INF/errors/404.jsp").forward(request, response);
}
else {
HttpSession session = request.getSession();
session.setAttribute("user", user);
request.getRequestDispatcher("/WEB-INF/users/show.jsp").forward(request, response);
}
}
}
Questions:
Is request.getParameterMap().isEmpty() the preferred way to test for the presence of parameters?
Is there a way to infer the views' location (/WEB-INF/users/) from the either the Servlet's context or an annotation?
Is request.getParameterMap().isEmpty() the preferred way to test for the presence of parameters?
Yes, it is. But this is not the right solution for your particular case. Your code will fail if the enduser supplied an arbitrary parameter with other name than name, causing the parameter map to be not empty and thus enter the block which expects the name parameter. You should really explicitly check the request parameter name itself.
String name = request.getParameter("name");
if (name == null) {
Collection<User> users = resource.getUsers();
// ...
}
else {
User user = resource.getUser(name);
// ...
}
Is there a way to infer the views' location (/WEB-INF/users/) from the either the Servlet's context or an annotation?
Use a MVC framework (recommended) or homebrew one (not recommended, unless 100% internal/private/hobby and thus for pure learning purposes).
The opposite of: How to manually log out a user with spring security?
In my app I have register new user screen, which posts to a controller which creates a new user within db (and does a few obvious checks).I then want this new user to be automatically logged in ... I kind of want somethign like this :
SecurityContextHolder.getContext().setPrincipal(MyNewUser);
Edit
Well I have almost implemented based on the answer to How to programmatically log user in with Spring Security 3.1
Authentication auth = new UsernamePasswordAuthenticationToken(MyNewUser, null);
SecurityContextHolder.getContext().setPrincipal(MyNewUser);
However, when deployed the jsp can not access my MyNewUser.getWhateverMethods() whereas it does when normal login procedure followed. the code that works nomrally, but throws an error when logged in like above is below :
<sec:authentication property="principal.firstname" />
In my controller i have this, which logs user in as normal :
Authentication auth =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
Where user is my custom user object(implementing UserDetails) that is newly created. The getAuthorities() method does this (just because all my users have the same role):
public Collection<GrantedAuthority> getAuthorities() {
//make everyone ROLE_USER
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
GrantedAuthority grantedAuthority = new GrantedAuthority() {
//anonymous inner type
public String getAuthority() {
return "ROLE_USER";
}
};
grantedAuthorities.add(grantedAuthority);
return grantedAuthorities;
}
You can also inject your spring security configured UserDetailsManager to your controller and use that to get the UserDetails which holds the principal and authorities to avoid duplicate code:
// inject
#Autowired
private UserDetailsManager manager;
// use in your method
UserDetails userDetails = manager.loadUserByUsername (token.getUsername ());
Authentication auth = new UsernamePasswordAuthenticationToken (userDetails.getUsername (),userDetails.getPassword (),userDetails.getAuthorities ());
SecurityContextHolder.getContext().setAuthentication(auth);
From the spring security source AbstractAuthenticationProcessingFilter:
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
Authentication authResult) throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
}
// you need this
SecurityContextHolder.getContext().setAuthentication(authResult);
rememberMeServices.loginSuccess(request, response, authResult);
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
successHandler.onAuthenticationSuccess(request, response, authResult);
}
Note however that the SecurityContextHolder is usually cleared upon completion of the filter chain.
For anyone trying to do this with Reactive Spring Security, this is what I did and it seemed to work.
private Mono<Authentication> authenticateUser(ServerWebExchange exchange, UserDetails userDetails,String rawPassword)
{
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails.getUsername(),rawPassword);
return reactiveAuthenticationManager.authenticate(token).filter(auth -> auth.isAuthenticated()).flatMap(auth ->
{
SecurityContextImpl securityContext = new SecurityContextImpl();
securityContext.setAuthentication(auth);
return securityContextRepository.save(exchange,securityContext).then(Mono.just(auth));
});
}
In a custom role provider (inheriting from RoleProvider) in .NET 2.0, the IsUserInRole method has been hard-coded to always return true:
public override bool IsUserInRole(string username, string roleName) { return true; }
In an ASP.NET application configured to use this role provider, the following code returns true (as expected):
Roles.IsUserInRole("any username", "any rolename"); // results in true
However, the following code returns false:
Roles.IsUserInRole("any rolename"); // results in false
Note that User.IsInRole("any rolename") is also returning false.
Is this the expected behavior?
Is it incorrect to assume that the overload that only takes a role name would still be invoking the overridden IsUserInRole?
Update: Note that there doesn't seem to be an override available for the version that takes a single string, which has led to my assumption in #2.
I looked at Roles.IsUserInRole(string rolename) in .net reflector, and it resolves to the following:
public static bool IsUserInRole(string roleName)
{
return IsUserInRole(GetCurrentUserName(), roleName);
}
I would take a look at your current user. Here's why:
private static string GetCurrentUserName()
{
IPrincipal currentUser = GetCurrentUser();
if ((currentUser != null) && (currentUser.Identity != null))
{
return currentUser.Identity.Name;
}
return string.Empty;
}
I would be willing to bet this is returning an empty string because you either don't have a Current User, or its name is an empty string or null.
In the IsUserInRole(string username, string roleName) method, there is the following block of code right near the beginning:
if (username.Length < 1)
{
return false;
}
If your GetCurrentUserName() doesn't return anything meaningful, then it will return false before it calls your overridden method.
Moral to take away from this: Reflector is a great tool :)
Also beware if you have selected cacheRolesInCookie="true" in the RoleManager config. If you have added a new role to the database, it might be looking at the cached version in the cookie.
I had this problem and the solution was to delete the cookie and re-login.
This may help someone - be aware:
If you are using the login control to authenticate - the username entered into the control becomes the HttpContext.Current.User.Identity.Name which is used in the Roles.IsUserInRole(string rolename) and more specifically - the membership's GetUser() method. So if this is the case make sure you override the Authenticate event, validate the user in this method and set the username to a value that your custom membership provider can use.
protected void crtlLoginUserLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
bool blnAuthenticate = false;
string strUserName = crtlLoginUserLogin.UserName;
if (IsValidEmail(strUserName))
{
//if more than one user has email address - must authenticate by username.
MembershipUserCollection users = Membership.FindUsersByEmail(strUserName);
if (users.Count > 1)
{
crtlLoginUserLogin.FailureText = "We are unable to determine which account is registered to that email address. Please enter your Username to login.";
}
else
{
strUserName = Membership.GetUserNameByEmail(strUserName);
blnAuthenticate = Membership.ValidateUser(strUserName, crtlLoginUserLogin.Password);
//setting the userLogin to the correct user name (only on successful authentication)
if (blnAuthenticate)
{
crtlLoginUserLogin.UserName = strUserName;
}
}
}
else
{
blnAuthenticate = Membership.ValidateUser(strUserName, crtlLoginUserLogin.Password);
}
e.Authenticated = blnAuthenticate;
}