Liferay Autologin Hook produces 'Your request failed to complete' in portlet - liferay

I've done a custom Autologin Filter which seems to works well, but when Liferay redirects to the main page (once the user has been authenticated), the login portlet shows an error that I cannot understand.
The error shows "Your request failed to complete", but the user has been successfully logged and if I press F5 or navigate through the page, the error disappear.
My Autologin class implementation is:
public String[] login(HttpServletRequest request,
HttpServletResponse response) throws AutoLoginException {
String[] credentials = new String[3];
String p_id = request.getParameter("p_p_id");
String userName = null;
String password = null;
if (p_id != null) {
userName = request.getParameter("_" + p_id + "_login");
password = request.getParameter("_" + p_id + "_password");
//Custom authentication code required [...]
}
if (userName != null) {
// New Login
try {
//We log as Test user...just for TEST
long companyId = PortalUtil.getCompanyId(request);
User user = UserLocalServiceUtil.getUserByScreenName(companyId, "Test");
long userId = user.getUserId();
String userPwd = user.getPassword();
credentials[0] = Long.toString(userId);
credentials[1] = userPwd;
credentials[2] = Boolean.FALSE.toString();
} catch (Exception e) {
e.printStackTrace();
throw new AutoLoginException(e);
}
return credentials;
}
return credentials;
}
I've also implemented a Custom Authenticator which always return SUCCESS.
Do you have any idea about what I'm doing wrong?
Thank you very much in advance!
Ivan fontanals

Related

ASP.NET MVC Core 3.0 after login shows login page again at the browser back button click

Once the user gets logged in and press the back button then the user needs to login again. I want to solve this issue. Can anyone have idea about it?
//startup.cs
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options=>
{
options.Cookie.Name = "Dementia.Cookie";
//options.EventsType = typeof(Infrastructure.Persistance.GenericUser);
options.LoginPath = "/Home/Login";
options.LogoutPath = "/Home/Logout";
options.ExpireTimeSpan = TimeSpan.FromMinutes(5); //TimeSpan.FromDays(1);
options.SlidingExpiration = false;
});
//Controller
[Authorize]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Dashboard()
{
return View();
}
I have manually stored in cookies dashboard url and validate the identity its working fine.
var claims = new[] {
new Claim(ClaimTypes.Name, userInfo.Name),
new Claim(ClaimTypes.Role, userInfo.Category),
new Claim(ClaimTypes.Uri, "/Home/Dashboard"),
new Claim("UserId", userInfo.UserId),
new Claim("Id", userInfo.Id)};
public IActionResult Login()
{
if (HttpContext.User.Identity.IsAuthenticated)
{
return Redirect(HttpContext.User.FindFirst(ClaimTypes.Uri).Value);
}
return View();
}

Test Method Implementation in jhipster

I need to implement a test method to cover the following method. But it is not compulsory to cover it for 100% coverage.
#DeleteMapping("/users/{login:" + Constants.LOGIN_REGEX + "}")
#Timed
#Secured({AuthoritiesConstants.ADMIN, AuthoritiesConstants.STUDENT})
public ResponseEntity<Void> deleteUser(#PathVariable String login) {
log.debug("REST request to delete User: {}", login);
boolean hasAuthorityStudent = false;
boolean hasAuthorityAdmin = false;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
hasAuthorityAdmin = authorities.contains(new SimpleGrantedAuthority(AuthoritiesConstants.ADMIN));
hasAuthorityStudent = authorities.contains(new SimpleGrantedAuthority(AuthoritiesConstants.STUDENT));
if (hasAuthorityAdmin) {
// delete user
userService.deleteUser(login);
return ResponseEntity.ok().headers(HeaderUtil.createAlert("userManagement.deleted", login)).build();
} else {
//get the authorities of the user who is going to be deleted
Optional<User> user = userService.getUserWithAuthoritiesByLogin(login);
Set<Authority> currentUserAuthorities = user.get().getAuthorities();
log.debug("REST request to delete User: {}", user);
log.debug("REST request to delete Member: {}", currentUserAuthorities);
boolean hasDeletedMembByStu = false;
if (hasAuthorityStudent) {
for (Authority auth : currentUserAuthorities) {
// delete user if it is a student
if (auth.getName().equals(AuthoritiesConstants.MEMBER)) {
userService.deleteUser(login);
hasDeletedMembByStu = true;
}
}
if (hasDeletedMembByStu) {
return ResponseEntity.ok().headers(HeaderUtil.createAlert("userManagement.deleted", login)).build();
}
}
return ResponseEntity.badRequest()
.headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "AccessDenied", "Lecturer can delete only members"))
.body(null);
}
}
I an using 4.8.2 as the jhipster version. I have attempted as follows.
#Test
#Transactional
public void deleteUser() throws Exception {
// Initialize the database
userRepository.saveAndFlush(user);
userSearchRepository.save(user);
restUserMockMvc.perform(delete("/api/users/{login}", user.getLogin())
.contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(status().isBadRequest());
}
There user is initialized with ROLE_USER. Then generated a build failure of the test method saying java.lang.AssertionError: Status expected:<400> but was:<500&gt
You are not logged in so authentication is null and authentication.getAuthorities() throws a NullPointerException.
To fix that you need to apply Spring-Security like here and assign a user and roles to your request like here.
Other note : instead of calling SecurityContextHolder.getContext().getAuthentication() you can get the principal directly in the controller method :
ResponseEntity<Void> deleteUser(#PathVariable String login, Principal principal) {
log.debug("REST request to delete User: {}", login);
boolean hasAuthorityStudent = false;
boolean hasAuthorityAdmin = false;
if (principal != null) {
Collection<? extends GrantedAuthority> authorities = principal.getAuthorities();
...

Getting UserId from MVC using WebMetrix

I'm using bellow login method to login in a MVC 5 application.
What I want to do is get the id of the user that is currently logged.
I tried to use these 2 methods:
// 1
// This one raise an exception:
Guid loggedUser = (Guid)Membership.GetUser().ProviderUserKey;
Additional information: Object reference not set to an instance of an
object.
// 2
// sets loggedUser variable to null
loggedUser = User.Identity.GetUserId();
// Login Method within Controller
public ActionResult Login(Login logindata, string ReturnUrl)
{
if (ModelState.IsValid)
{
if (WebSecurity.Login(logindata.Username, logindata.Password))
{
if (ReturnUrl != null)
{
return Redirect(ReturnUrl);
}
return RedirectToAction("Index", "Home");
}
}
ModelState.AddModelError("", "Sorry the username or password is invalid ");
return View(logindata);
}
My question is what I'm doing wrong and if it's possible to get the logged user id like this???
Thanks
I used this method and worked:
WebSecurity.GetUserId("loggedUser")

ASP.NET Identity: UserManager.PasswordHasher.VerifyHashedPassword keeps failing

I'm using ASP.NET Identity 2 with Entity Framework 5 (because our Oracle data provider does not support EF6). For some reason the password verification by means of UserManager.PasswordHasher.VerifyHashedPassword keeps failing.
My UserStore class contains:
public Task SetPasswordHashAsync(IccmUser user, string passwordHash)
{
IPasswordHasher hasher = new PasswordHasher();
var t = Task.Run(() => {
user.PasswordHash = hasher.HashPassword(passwordHash);
});
return t;
}
The (obviously hashed) password is stored in the database. Thus, this code seems to work just fine.
My AccountController does the password verification like this:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(SignInModel model, string returnUrl)
{
if (ModelState.IsValid) {
// This fails:
//var user = await UserManager.FindAsync(model.UserName, model.Password);
// Thus: do it step by step.
PasswordVerificationResult result = PasswordVerificationResult.Failed;
// Step 1: find user.
IccmUser user = await UserManager.FindByNameAsync(model.UserName);
if (user == null) {
ModelState.AddModelError("", "Couldn't find the user.");
} else {
// Step 2: validate password
result = UserManager.PasswordHasher.VerifyHashedPassword(user.PasswordHash, model.Password);
if (result != PasswordVerificationResult.Success) {
ModelState.AddModelError("", "The password is not valid.");
} else {
// Step 3: sign-in user.
await SignInAsync(user, model.RememberMe);
return Redirect(returnUrl);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
The VerifyHashedPassword() in step 2 always returns Failed. Both parameters (PasswordHash and Password) are passed in correctly.
Any pointers to what I'm missing are greatly appreciated.
The error is in the UserStore implementation. SetPasswordHashAsync() is not supposed to hash the password. Instead, it receives the hashed password from UserManager.CreateAsync(). Thus, the following change in UserStore does the trick:
public Task SetPasswordHashAsync(IccmUser user, string passwordHash)
{
return Task.FromResult(user.PasswordHash = passwordHash);
}
Sorry for the noise.

How to use HttpServletRequest#login() programmatic login with SHA-256 configured security realm

i have read there, i am using glassfish 3.1.1 security realm configured with sha-256 digest algorithm. is there any tutorial about this ? maybe i am blethering, i am trying to login with this code:
public void login() throws NoSuchAlgorithmException {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
EntityManager em = emf.createEntityManager();
boolean committed = false;
try {
FacesMessage msg = null;
EntityTransaction entr = em.getTransaction();
entr.begin();
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes());
byte byteData[] = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
password = sb.toString();
Query query = em.createQuery("SELECT COUNT(u) FROM EntityUser u WHERE u.userName = :userName AND u.password = :password")
.setParameter("userName", userName).setParameter("password", password);
long result = (long)query.getSingleResult();
if (result == 1) {
request.login(userName, password);
msg = new FacesMessage();
msg.setSeverity(FacesMessage.SEVERITY_INFO);
msg.setSummary("You are logged in");
}
entr.commit();
committed = true;
} catch (ServletException e) {
context.addMessage(null, new FacesMessage("wrong username or password"));
}
finally {
if (!committed) entr.rollback();
}
} finally {
em.close();
}
}
result variable returns 1, but request.login(userName, password); method in if condition always throws servletexception.
Can you post the exception stacktrace? That way it would be easier to understand the source of the exception. But judging from your currently supplied code, you should supply in
request.login(userName, password);
the password as the plain-text password and not the hashed password.
Interface HttpServletRequest
ServletException - if the configured login mechanism does not support username password
authentication, or if a non-null caller identity had already been established (prior to
the call to login), or if validation of the provided username and password fails.
There can be a lot of reasons that login fails. You've just checked if appropriate user and password are in table. Glassfish makes two queries - in authenticate process - to two tables. One to table specified as userTable, and second to groupTable which are determined in security realm definition. Check if web.xml and glassfish-web.xml are correct too.
the questioned problem is whole about method
request.login(userName, password);
Author made everything right, even his own authentication way of working with users database, but request.login needs for authentication realm be set up, to be used by this method. And you have your own, you dont need separate request.login authentication. For the case you need it - thats how you do it jdbc-realm-setup-with-glassfish-v3
So, after you get the result=1, you set up your context.getExternalContext().getSessionMap().put("user", u);
and send redirection context.getExternalContext().redirect(context.getExternalContext().getRequestContextPath() + "какой-то модуль.xhtml");
and use webfilter to block access to /Pages/*.xhtml without logging in.
#WebFilter("/Pages/*")
public class LoggingFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
User user = (User) req.getSession().getAttribute("user");
if(user != null){
chain.doFilter(request,response);
}
else res.sendRedirect(req.getContextPath()+"/запрос_учетных_данных.xhtml");
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}

Resources