How do I extract the username and password out of a URL in a servlet filter? - servlets

I've created a BasicAuthFilter and it has this signature:
#Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException
This is working if someone calls the filter with an Authorization header set the right way. But, if someone on chrome or firefox visits the url like this:
http://username:password#localhost:8888
The browsers are not populating the Authorization header with that information (which surprised me). I looked at the information sent by chrome and the username and password are in the request URL but nowhere else.
I can't figure out how to extract that information from the URL. I've tried a lot of getters on the HttpServletRequest, but haven't found anything that gives me the username and password.
NOTE: Yes, I know this is insecure, it's just really convenient to use when you're trying to test your system.

URL url = new URL(custom_url);
String userInfo = url.getUserInfo();
String[] userInfoArray = userInfo.split(":");
System.out.println("username"+userInfoArray[0]);
System.out.println("password"+userInfoArray[1]);

My coworker found this thread that implies this isn't possible in modern browsers. They refuse to send the username:password part of a url over the wire for security reasons.

I'll add something to this answer
If the password contains the character :, you must specify a limit on your split.
So:
String[] userInfoArray = userInfo.split(":");
Becomes:
String[] userInfoArray = userInfo.split(":", 2);
2 means the pattern : is applied only one time (so the resulting length array is at maximum 2)

For passwords with '#', e.g. "http://user:p#ssw0rd#private.uri.org/some/service":
final String authority = uri.getAuthority();
if (authority != null) {
final String[] userInfo = authority.split(":", 2);
if (userInfo.length > 1) {
this.username = userInfo[0];
int passDelim = userInfo[1].lastIndexOf('#');
if (passDelim != -1) {
this.password = userInfo[1].substring(0, passDelim);
}
}
}
Note that in this case trying to use getUserInfo() won't help since userInfo of the URI is null.

Related

Get beautified URL from HttpServletRequest

I am using the org.omnifaces.filter.HttpFilter to redirect visitors on login page when nobody is logged in.
#Override
public void doFilter(HttpServletRequest req, HttpServletResponse res, HttpSession session, FilterChain chain) throws ServletException, IOException {
String loginUrl = "/myapp/login?redirect_url=" + req.getRequestURL();
boolean loggedIn = (req.getRemoteUser() != null);
if (loggedIn) {
chain.doFilter(req, res); // So, just continue request.
} else {
Servlets.facesRedirect(req, res, loginUrl);
}
}
I want to redirect not logged in users to /login?redirect_url=previous_page_url
The problem is that all my URLs are beautified by pretty-faces and when I try to get the previous URL with HttpServletRequest.getRequestURI(), it gives me the ugly URL.
For example, I configured an url /myapp/my-page-3 which displays /views/module1/page3.xhtml.
But HttpServletRequest.getRequestURI() is giving me /views/module1/page3.xhtml and not /myapp/my-page-3.
Any ideas ?
When the servlet based URL rewrite engine uses under the covers RequestDispatcher#forward() to forward an incoming friendly-URL request to the desired resource, then you can use request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI) to find out the original request URI.
String originalRequestURI = request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
As you're already using OmniFaces, you can use Servlets#getRequestURI() to automatically detect it and return it when present, else fall back to the default HttpServletRequest#getRequestURI().
String requestURI = Servlets.getRequestURI(request);

Spring OAuth2 - URL Encoded of username within Basic auth header for token endpoint

It seems that Basic Auth for token endpoint is not compliant with OAuth2.0 spec, which specifies that the username and password should be URL encoded before being joined with a colon and the base 64 encoded. See rfc6749
Creation of the header should be:
auth_header = 'Basic' + base64 (urlEncode (client_id) + ':' + urlEncode (client_secret))
Hence there needs a URL decode step after splitting the username from the password.
Spring is just using the BasicAuthenticationFilter to extract the credentials and there doesn't seem a way of extending this to add the URL Decode step.
So, is this an omission from Spring security OAuth2? If so, guess a bug should be raised.
I could replace the BasicAuthenticationFilter, with one that has the URL Decode step, but is there an easier way?
I am currently using Spring Security 5.0.5
Spring security does comply with OAuth 2.0 spec. What you're asking is already covered in BasicAuthenticationFilter. Here's an excerpt from the code:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean debug = this.logger.isDebugEnabled();
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Basic ")) {
try {
String[] tokens = this.extractAndDecodeHeader(header, request);
assert tokens.length == 2;
Filter reads the header that has Basic authentication, then it extracts and decode the credentials.
In the following code, notice that index of colon is used as a String delimiter.
private String[] extractAndDecodeHeader(String header, HttpServletRequest request) throws IOException {
byte[] base64Token = header.substring(6).getBytes("UTF-8");
byte[] decoded;
try {
decoded = Base64.getDecoder().decode(base64Token);
} catch (IllegalArgumentException var7) {
throw new BadCredentialsException("Failed to decode basic authentication token");
}
String token = new String(decoded, this.getCredentialsCharset(request));
int delim = token.indexOf(":");
if (delim == -1) {
throw new BadCredentialsException("Invalid basic authentication token");
} else {
return new String[]{token.substring(0, delim), token.substring(delim + 1)};
}
}

can't get a response out of eBay's Merchandising API

This is my first question.. ever... for this illustrious and reverential forum, so if I am rebuked for the content of this question I won't take it personally...
I am attempting to call ebay's merchandising service via the code below, and keep getting a "The request failed with an empty response." err Response
static void Main(string[] args)
{
//Use the custom class
customMerchandisingService svc = new customMerchandisingService();
//Set the production URL
svc.Url = "http://svcs.ebay.com/MerchandisingService?";
GetMostWatchedItemsRequest request = new GetMostWatchedItemsRequest();
request.categoryId = "617";
MerchandisingServiceItemResponse response = svc.getMostWatchedItems(request);
foreach (Item item in response.itemRecommendations)
{
//process results
string title = item.title;
string itemID = item.itemId;
}
}
class customMerchandisingService : MerchandisingAPI.MerchandisingService
{
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
HttpWebRequest req = (HttpWebRequest)base.GetWebRequest(uri);
//Set the AppID, Operation, Service, Protocol and Version as HTTP Headers
req.Headers.Add("EBAY-SOA-CONSUMER-ID", "Your AppID");
req.Headers.Add("X-EBAY-SOA-OPERATION-NAME", "getMostWatchedItems");
req.Headers.Add("X-EBAY-SOA-SERVICE-NAME", "MerchandisingService");
req.Headers.Add("X-EBAY-SOA-MESSAGE-PROTOCOL", "SOAP11");
req.Headers.Add("X-EBAY-SOA-SERVICE-VERSION", "1.1.0");
return req;
}
}
I googled a bit, and read posts such as the following:
"The request failed with an empty response" when calling a web service
I tried playing with my httpeepee's, and keep coming up short. Basically I was hoping that it wasn't me, that some web developer at eBay (bless his heart) was to blame, today at least.
I guess I was hoping someone on this forum that also develops against eBay's API's could confirm that the merchandising service is working fine for them today, in which case I guess I'll need to keep banging my head against a wall.
Thanks in advance.

reading from a text file in servlets

i have a login servlet from where i take a username and a password. i have a credentials.txt file where i have saved a few usernames followed by their passwords adjacently in a single line. once i read the username and password in my logincheck servlet, i want to search it in credentials.txt. if a match is found, we are directed to a welcomepage servlet, and if not found, we are again directed to the login servlet. i am getting array out of bounds exception in my code.
Plz help correct my code.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String user=request.getParameter("username");
String pass=request.getParameter("password");
File obj=new File("credentials.txt");
FileReader reader=new FileReader(obj);
BufferedReader in=new BufferedReader(reader);
String aks[],temp1,temp2;
int i=0;
String line=in.readLine();
while(line!=null){
aks=line.split("\t");
while(aks[i+1]!=null){
temp1=aks[i];
temp2=aks[i+1];
if(temp1.equals(user) && temp2.equals(pass)){
RequestDispatcher obj1=request.getRequestDispatcher("welcomepage");
obj1.forward(request,response);
}
line=in.readLine();
}
}
String errormsg="username and password do not match. Please re-enter";
request.setAttribute("errormsg",errormsg);
RequestDispatcher obj1=request.getRequestDispatcher("login");
obj1.forward(request,response);
}
It looks like you're thinking that aks[i+1]!=null will evaluate to false if the element aks[i+1] doesn't exist. But if the element doesn't exist, it won't evaluate to anything; you'll always the exception you mentioned (index out of bounds). Seems like maybe what you're looking to do is actually while (aks.length>1).

spring-mvc with resteasy character encoding problem on jetty server

I am trying to implement restful protocol on jetty server. I have runnable server and i can access it from my rest client. My server side project is a maven project. I have a problem about the character encoding.When i check response, before send it from controller, there is no encoding problem. But after i return response to client, i see broken data. Response header is UTF-8. Also i have a listener for this problem and i am setting to request and response to UTF-8. I guess problem happens when i try to write my response data to response.
#GET
#Path("/")
#Produces({"application/xml;charset=UTF-8","application/json;charset=UTF-8"})
public String getPersons(#Context HttpServletRequest request, #Context HttpServletResponse response) {
List<Person> persons = personService.getPersons(testUserId, collectionOption, null);
if (persons == null) {
persons = new ArrayList<Person>();
}
String result = JsonUtil.listToJson(persons);
//result doesnt has any encoding problem at this line
response.setContentType("application/json");
response.setContentLength(result.length());
response.setCharacterEncoding("utf-8");
//i guess problem happen after this line
return result;
}
Is there any jetty configuration or resteasy configuration for it? Or is there any way to solve this problem? Thanks for your helps.
Which resteasy version are you using? There is a known issue (RESTEASY-467) with Strings in 2.0.1 an prior.
These are your options:
1) force the encoding returning byte[]
public byte[] getPersons
and then
return result.getBytes("UTF8");
2) return List (or create a PersonListing if you need it)
public List<Person> getPersons
and let resteasy handle the json transformation.
3) return a StreamingOutput
NOTE: with this option the "Content-Length" header will be unknown.
return new StreamingOutput()
{
public void write(OutputStream outputStream) throws IOException, WebApplicationException
{
PrintStream writer = new PrintStream(outputStream, true, "UTF-8");
writer.println(result);
}
};
4) upgrade to 2.2-beta-1 or newer version.

Resources