I have a simple web-app deployed in Apache Tomcat which has a login page, an upload form and a logout button.
When the login form is submitted I am checking for the credentials and redirecting it to the upload page if the login is successful and if not I am re-directing the request to the login page itself.
I also have a Filter (javax.servlet.Filter) that authenticated whether each request is from a logged in user.
All was working fine yesterday, but come today even with a valid username/password I am redirected to the login page. This only happens in Chrome.
If I use Firefox or open a incognito window in chrome the flow works perfectly fine.
When I debugged, I see that request.session returns null when a redirection is made on a successful login.
My LoginServlet:
if (success) {
........
...........
HttpSession session = request.getSession(true);
session.setAttribute(WebAppConstants.OAUTH_TOKEN_SESSION_ATTRIB, accessToken);
session.setAttribute(WebAppConstants.USER_SESSION_ATTRIB, username);
session.setAttribute(WebAppConstants.IS_LOGGED_IN_SESSION_ATTRIB, true);
session.setMaxInactiveInterval(30 * 60);
Cookie usernameCookie = new Cookie(WebAppConstants.USER_SESSION_ATTRIB, username);
usernameCookie.setMaxAge(30 * 60);
response.addCookie(usernameCookie);
response.sendRedirect(WebAppConstants.UPLOADER_JSP);
} else {
response.sendRedirect(WebAppConstants.INVALID_LOGIN_JSP);
}
My LoginCheckFilter:
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpSession session = request.getSession(false);
String loginURI = request.getContextPath() + "/login.html";
String uri = request.getRequestURI();
this.context.log("Requested Resource::" + uri);
if (session == null && !(uri.endsWith("html") || uri.endsWith("login"))) {
this.context.log("Unauthorized access request");
response.sendRedirect(loginURI);
} else {
filterChain.doFilter(request, response); // Logged-in user found, so just continue request.
}
}
Why is this happening with the Chrome browser?? Have I handled stuff correctly.
Thank You
I tried removing cookies in Chrome and my login chain worked without an issue.
However, I am still trying to get a clear understanding of what actually happened (with chrome) and how did clearing cookies help me.
EDITED:
As per Shadab Faiz's comment above the below answer seems accurate and thus am accepting it:
What happens is that sometimes browser may store previous request data. So when you input wrong credentials, it stored that request. So from next one onwards, whenever you inputted correct info, the previous request with wrong info was sent.
Thanks
Related
I am using spring security with the below configurations.
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http
.securityContextRepository(securityContextRepository)
.authorizeExchange()
.anyExchange().authenticated()
.and()
.formLogin().disable()
.httpBasic().disable()
.csrf().disable()
.logout().disable();
return http.build();
}
And my ShipxpressReactiveSecurityContextRepository load method looks like below.
#Override
public Mono<SecurityContext> load(ServerWebExchange serverWebExchange) {
String authorization = CollectionToolkit.getFirstElement(
serverWebExchange.getRequest().getHeaders().get(ShipxSecurityConstant.Header.AUTHORIZATION_HEADER));
if (StringToolkit.isNotEmpty(authorization)) {
return authenticate(authorization, serverWebExchange);
} else {
return Mono.empty();
}
}
My use case is properly working. but my issue is here when I try to access my API from the browser (ex : localhost:8180/dmu) Spring browser prompt to authentication. in that situation if i enter the wrong user / password i cant change it with next request.
Because There is a "Authorization" request header with invalid authentication.
I have two questions.
How we can remove default request headers from the browser ( access get methods from browser URL)
how i can disable to generate default request headers from spring.
Example screenshot:
I am creating a login server using Identityserver4. I am using ASP.net core 3.1 for functionality, and angular 9 project for serving static files for login/registeration screens. The angular project is being served from within the .netcore project's wwwroot folder.
My flow goes like this
javascript client calls OIDC user manager's signInRedirect() method with following configurations
This sends a call to my Login method to render the angular's login component. Once the user fills in credentials, a second call is sent to my Login method return this.http.post('Account/Login', {UserName, Password, ReturnUrl}, {headers, responseType:'text'});
On successfull login, I do a return Redirect(model.returnUrl);
[HttpGet]
public IActionResult Login(string returnUrl)
{
return Redirect("/login?ReturnUrl=" + WebUtility.UrlEncode(returnUrl));
}
[HttpPost]
public IActionResult Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = _userManager.FindByNameAsync(model.UserName).Result;
var result = _signInManager.PasswordSignInAsync(model.UserName, model.Password, false, false).Result;
if(result.Succeeded)
{
return Redirect(model.ReturnUrl);
}
return Ok(new Error { ErrorMessage = "Invalid credentials" });
}
return Ok(new Error { ErrorMessage = "Some error" });
}
In my network tab, I can see that the return Url which is a call to IdentityServer's authorization endpoint /connect/authorize/callbackis successfull.
It has also made a second call to the actual javascript client in point 1 with the authentication successfull.
However, the problem arises here. This request is returning the HTML as string of the JS clients callback.html instead of actually redirecting to that URL(http://localhost:5003/callback.html)
I don't even have any way to access the URL of the returned HTML, otherwise I would have done a window.location.href. How do I capture the URL of the callback page in angular and redirect to it ?
I would need a few more details to remedy this particular situation. However, I did want to offer my expertise in the form of explaining how this is supposed to work. I have an NPM library imng-auth0-oidc that does this very thing, except that it uses NGRX.
Your callback.html should be a static (non-Angular) HTML page. You can find a copy here callback.html. The purpose of this page is to receive the OAUTH2 response and store the token in localStorage, then redirect the response to your Angular application. Once the application is loaded, you'll now have access to your token that is waiting in localStorage.
-Isaac
In GWT when RPC fail due to any reason at that time onfailure() method execute at client side.
When onFailure() called at that time actual error is visible in browser's Networks response.
So, My Question is simple how can hide / Modify this actual error with some user friendly Error?
You can override onFailure() method to display what you need, but you cannot modify what a browser shows in the Network tab.
This is an example from my code (LoginException and VersionException are exceptions that my RPC calls throw when necessary):
#Override
public void onFailure(Throwable caught) {
if (caught instanceof LoginException) {
// Redirect a user to login page
Window.Location.assign("/");
} else if (caught instanceof IncompatibleRemoteServiceException ||
caught instanceof VersionException) {
/*
* Here I tell a user that a new version is available,
* so a user needs to refresh the page
*/
} else {
// Here I show a simple message about a connection error
}
}
When our Android client doest a request to our server with Apache HTTP client I want it to redirect to a new url (or more specific, an other context path) with the same HTTP method.
In my httpd.conf I sat up this rule with status code 307:
Redirect 307 /mybipper/reg /mybipperapi/old/reg
According to the status code description in Wikipedia a 307 should:
http://en.wikipedia.org/wiki/HTTP_307#3xx_Redirection
307 Temporary Redirect (since HTTP/1.1)
In this case, the request should be repeated with another URI; however, future requests can still use the original URI.[2] In contrast to how 302 was historically implemented, the request method should not be changed when reissuing the original request. For instance, a POST request must be repeated using another POST request.
But in my access log we see that HTTP client doesnt seem to respect it and executes a GET instead just as if I returned a status code 302
172.29.9.120 - - [21/Sep/2012:14:02:11 +0300] "POST /mybipper/reg HTTP/1.1" 307 248
172.29.9.120 - - [21/Sep/2012:14:02:11 +0300] "GET /mybipperapi/old/reg HTTP/1.1" 400 1016
According to Apache HTTP Client web site its a bit unclear how it should handle status code 307, but they list it at least there.
http://hc.apache.org/httpclient-3.x/redirects.html
I have a strong feeling its Apache HTTP client which doesn't implement the HTTP 1.1 protocol correctly, am I correct or have I misunderstood something?
The Apache HTTP client we use is bundled with the Android SDK. The phone I was testing on had Android SDK 15, ergo this one:
http://developer.android.com/about/versions/android-4.0.3.html
The DefaultRedirectStrategy only allows GET and HEAD to be redirected automatically. If you want to also allow POST (but not PUT or DELETE), you can switch to the LaxRedirectStrategy by doing something like:
HttpClientBuilder hcb = HttpClients.custom();
hcb.setRedirectStrategy(new LaxRedirectStrategy());
HttpClient client = hcb.build();
If you want to also follow PUT and DELETE (like we do here), you'll have to implement a custom strategy (note: we ran into a bug in the HttpClient where it appears it was trying to add a second Content-Length header when we do this, so we manually remove it. YMMV). By using this strategy, HttpClient will also support 308 redirects, something the Apache team couldn't even be bothered to include.
You can do something like this:
hcb.setRedirectStrategy(new DefaultRedirectStrategy() {
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
Args.notNull(request, "HTTP request");
Args.notNull(response, "HTTP response");
int statusCode = response.getStatusLine().getStatusCode();
switch(statusCode) {
case 301:
case 307:
case 302:
case 308:
case 303:
return true;
case 304:
case 305:
case 306:
default:
return false;
}
}
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
URI uri = this.getLocationURI(request, response, context);
String method = request.getRequestLine().getMethod();
if(method.equalsIgnoreCase("HEAD")) {
return new HttpHead(uri);
} else if(method.equalsIgnoreCase("GET")) {
return new HttpGet(uri);
} else {
int status = response.getStatusLine().getStatusCode();
HttpUriRequest toReturn = null;
if(status == 307 || status == 308) {
toReturn = RequestBuilder.copy(request).setUri(uri).build();
toReturn.removeHeaders("Content-Length"); //Workaround for an apparent bug in HttpClient
} else {
toReturn = new HttpGet(uri);
}
return toReturn;
}
}
});
To expand on Cody's correct answer - if you need to follow PUT (or any other method) 307 redirects then you can alternatively extend LaxRedirectStrategy which is even easier:
hcb.setRedirectStrategy(new LaxRedirectStrategy()
{
protected boolean isRedirectable(String method)
{
return "PUT".equalsIgnoreCase(method)||super.isRedirectable(method);
}
});
However that will not fix the issue of following 308s as well. I know this is an old question but I hit the same issue just today (thanks Cody).
if you want to add 308 as well to LaxRedirectStrategy - see code below
.setRedirectStrategy(new LaxRedirectStrategy() {
#Override
public boolean isRedirected(
final HttpRequest request,
final HttpResponse response,
final HttpContext context) throws ProtocolException {
Args.notNull(request, "HTTP request");
Args.notNull(response, "HTTP response");
final int statusCode = response.getStatusLine().getStatusCode();
final String method = request.getRequestLine().getMethod();
final Header locationHeader = response.getFirstHeader("location");
switch (statusCode) {
case HttpStatus.SC_MOVED_TEMPORARILY:
return isRedirectable(method) && locationHeader != null;
case HttpStatus.SC_MOVED_PERMANENTLY:
case HttpStatus.SC_TEMPORARY_REDIRECT:
return isRedirectable(method);
case HttpStatus.SC_SEE_OTHER:
return true;
case 308:
return true;
default:
return false;
} //end of switch
}
})
.build();```
I am writing a bulk email program using the JavaMail api. I have a Microsoft Exhange server which I am trying to send the emails in to. When I run my program I get the following error:
**com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2057)
at com.sun.mail.smtp.SMTPTransport.finishData(SMTPTransport.java:1862)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1100)
at javax.mail.Transport.send0(Transport.java:195)
at javax.mail.Transport.send(Transport.java:124)
at SendEmail.postMail(SendEmail.java:100)
at EmailGenerator.main(EmailGenerator.java:52)**
The part of my code trying to send the message is as follows:
Properties props = new Properties();
props.put("mail.smtp.host", email_server);
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", true);
class EmailAuthenticator extends Authenticator {
String user;
String pw;
EmailAuthenticator (String FROM, String PASSWORD)
{
super();
this.user = FROM;
this.pw = PASSWORD;
}
public PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(user, pw);
}
}
Session session = Session.getInstance(props, new EmailAuthenticator(USER, PASSWORD));
session.setDebug(debug);
System.out.println("Session created");
.. CREATED MESSAGE HERE...
Transport transport = session.getTransport("smtp");
transport.connect(exchange_server,user,password);
transport.send(msg);
transport.close();
I wonder am I missing some configuration on the Exchange server side, or is an issue with my code?
OK I figured out where I was going wrong here and am posting up the answer incase anybody else can get some value out of it. I had the following line of code:
props.put("mail.smtp.auth", true);
This was telling my application that it needed to authenticate to the SMTP server, when in fact it didnt. This was causing my application from logging into the SMTP server and sending the email and thus producing the error message. Setting this property to false or not having this line of code fixed the issue for me. This line of code is only necessary for SMTP servers that require you to login, which my Exchange server didnt.