Why number sign ignore in url? - web-services

I should develop a web service with rest by jersey to parse below url:
http://localhost:8080/userApp/processMsg/request?Username=$username&LastName=$lastName&Message=$Message&SessionId=$sessionId
I used below code and worked properly:
#POST
#Path("/request")
#Produces(MediaType.APPLICATION_XML + ";charset=utf-8")
public UserResponse getUsers(#QueryParam("Username") String Username,
#QueryParam("LastName") String LastName,
#QueryParam("Message") String Message,
#QueryParam("SessionId") String SessionId
) {
// my code
}
My problem is when I there is '#' character in the url, in this case, from this character to end of the url, will be ignored. I can't make any changes to url format and # sign always exist at the end of message field.
for avoiding this, I added a filter to my web.xml, with this code:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain next)
throws IOException, ServletException
{
// Respect the client-specified character encoding
// (see HTTP specification section 3.4.1)
if(null == request.getCharacterEncoding())
request.setCharacterEncoding(encoding);
/**
* Set the default response content type and encoding
*/
response.setContentType("text/html; charset=UTF-8");
response.setCharacterEncoding("UTF-8");
next.doFilter(request, response);
}
but the value of request.getParameterMap() was same of the previous,and there isn't end of the url. for example when I have in url:
http://localhost:8080/userApp/processMsg/request?Username=$test&LastName=$test2&Message=$HelloWorld#&SessionId=$123456, what my application received in url, is :
http://localhost:8080/userApp/processMsg/request?Username=$test&LastName=$test2&Message=$HelloWorld
how can I handle this problem?

pound (#) sign is reserved character in a URL. You need to URL encode it.
http://someurl?Message=$HelloWorld%23&otherParam
http://localhost:8080/userApp/processMsg/request?Username=$test&LastName=$test2&Message=$HelloWorld%23&SessionId=$123456
the pound sign is used for "anchor".
Spaces, and other special characters all need to be URL Encoded

Related

Spring Get endpoint returning 406 when special character is in pathVariable

I have endpoint:
#GetMapping(value = "/f{url:.*}")
public ResponseEntity<byte[]> read(#PathVariable("url") String url) {
...
}
When i try to get with:
https://baseUrl/f2Fretail
Then i get 200
But when I try:
https://baseUrl/f%2Fretail
I get 406.
I changed security to use:
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowSemicolon(true);
firewall.setAllowUrlEncodedPercent(true);
firewall.setAllowBackSlash(true);
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}
I want to get always 200 here and that Spring process % in {url} section or another characters as regular one and store it in url variable.
Cause of contract i have to use PathVariable here.
When i removed headers i get:
{
"timestamp": "2021-07-13T11:04:48.448+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "favbb/bbb"
}
Your URL not broken due that encoding. If broken you will get bad request - 400 or not found - 404.
406 - something wrong with your header. Add accept all in controller level.
Issue not with your encoding. Not able to return data. Your return some byte[] that not acceptable from front end.
Try to return some string instead of byte check whether your API working or not.

Establish SSO/set cookies with access or id token/token exchange

I'm allowing users logged in an external application to jump into our application with their access token through Keycloak's identity brokering and external to internal token exchange.
Now I'd like to establish an SSO session in an embedded JxBrowser in our application similar to a regular browser login flow, where three cookies are set in the browser: AUTH_SESSION, KEYCLOAK_SESSION(_LEGACY) and KEYCLOAK_IDENTITY(_LEGACY).
KEYCLOAK_IDENTITY contains a token of type Serialized-ID which looks somewhat similar to an ID token.
Is it possible to create the KEYCLOAK_IDENTITY cookie using the exchanged (internal) access and/or ID token and, provided that the other two cookies are correctly created as well, would this establish a valid SSO session?
Basically all I am missing is how I could obtain or create the Serialized-ID type token.
One way to achieve this:
Implement a custom endpoint following this example
Note that the provider works fine for me without registering it in standalone.xml, I'm just adding the JAR to the Keycloak Docker image.
Add a method that validates a given access token, looks up the user, gets the user session and sets the cookies in the response (most error handling omitted for brevity):
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("sso")
public Response sso(#Context final HttpRequest request) {
final HttpHeaders headers = request.getHttpHeaders();
final String authorization = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
final String[] value = authorization.split(" ");
final String accessToken = value[1];
final AccessToken token = Tokens.getAccessToken(accessToken, keycloakSession);
if (token == null) {
throw new ErrorResponseException(Errors.INVALID_TOKEN, "Invalid access token", Status.UNAUTHORIZED);
}
final RealmModel realm = keycloakSession.getContext().getRealm();
final UriInfo uriInfo = keycloakSession.getContext().getUri();
final ClientConnection clientConnection = keycloakSession.getContext().getConnection();
final UserModel user = keycloakSession.users().getUserById(token.getSubject(), realm);
final UserSessionModel userSession = keycloakSession.sessions().getUserSession(realm, token.getSessionState());
AuthenticationManager.createLoginCookie(keycloakSession, realm, user, userSession, uriInfo, clientConnection);
return Response.noContent().build();
}
Disclaimer: I am not completely certain this implementation does not imply any security issues, but since Tokens.getAccessToken(accessToken, keycloakSession) does full validation of the access token, setting the cookies should only be possible with a valid access token.
For CORS, add:
#OPTIONS
#Produces(MediaType.APPLICATION_JSON)
#Path("sso")
public Response preflight(#Context final HttpRequest request) {
return Cors.add(request, Response.ok("", MediaType.APPLICATION_JSON))
.auth()
.preflight()
.allowedMethods("GET", "OPTIONS")
.build();
}
and in sso():
return Cors.add(request, Response.ok("", MediaType.APPLICATION_JSON))
.auth()
.allowedMethods("GET")
.allowedOrigins(token)
.build();
What I am uncertain about is why Firefox preflights the GET request, making it necessary to handle that.

How to do server and client side validation which should only accept URL in textbox?

I want to do client and server side validation for Textbox which should only accept URL. I am not able find any link which does the same.
Can anyone please provide some ideas?
#Html.TextBoxFor(m => URl })
There is already a UrlAttribute in the System.ComponentModel.DataAnnotations that you can apply to your property to give both client and server side validation.
[Url] // Add optional (ErrorMessage = "...") as required
public string Url { get; set; }
Internally, it uses the following regex (from source code)
^(https?|ftp)://(((([a-z]|\d|-|.||~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'()*+,;=]|:)*#)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]).(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]).(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]).(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|.||~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))).)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))).?)(:\d*)?)(/((([a-z]|\d|-|.||~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'()*+,;=]|:|#)+(/(([a-z]|\d|-|.||~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'()*+,;=]|:|#)))?)?(\?((([a-z]|\d|-|.||~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'()*+,;=]|:|#)|[\uE000-\uF8FF]|/|\?)*)?(#((([a-z]|\d|-|.||~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'()*+,;=]|:|#)|/|\?)*)?$
You can use a RegularExpression validation in your model:
[StringLength(200)]
[RegularExpression(#"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+#)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+#)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%#.\w_]*)#?(?:[\w]*))?)", ErrorMessage = "Not a valid website URL")]
public string MyUrlField { get; set; }
I have found the above regex for matching a url from here. You could also check this website for other regex which would match a url.
Note that you need to include jquery-validation-unobtrusive, for the client side validation.
You can do URL Validation using regex for validation.
^http(s)?://([\w-]+.)+[\w-]+(/[\w- ./?%&=])?$
OR
/^http(s)?://([\w-]+.)+[\w-]+(/[\w- ./?%&=])?$/
You can this regex in both Server-Side and Javascript.
check it on : JSFIDDLE

Get username and password from http git URL

I have my own custom git servlet implemented using GitServlet.
I have my own authentication.
To clone or push, pull i want to authenticate against my authentication plugin.
To do this i need to read user/password from url given by user.
Like,
git clone http://sohanb:welcome#localhost:8080/git.ctr-0.0.1-SNAPSHOT/portal/.git
How can i get the usernmae i.e sohanb and password i.e welcome.
Updated question:
My git init code,
public void init(ServletConfig config) throws ServletException {
username = config.getInitParameter("username");
password=config.getInitParameter("password");
idpUrl=config.getInitParameter("idpUrl");
System.out.println("IDP URL is =======>> " + idpUrl);
setRepositoryResolver(new RepositoryResolver<HttpServletRequest>() {
public Repository open(HttpServletRequest req, String name) throws RepositoryNotFoundException,
ServiceNotEnabledException {
try {
System.out.println("name =============>> " +name);
System.out.println("parmrs if any ==========>> " + req.getParameterMap());
System.out.println("URL ===============>>" + req.getRequestURL().toString());
URL url = new URL(req.getRequestURL().toString());
System.out.println("Trying to get uswer info if any ====>> " +url.getUserInfo());
File gitParentFolder = new File("D:\\sigma-admin\\git.ctr\\git");
File gitRepoFolder = new File(gitParentFolder, name);
System.out.println("gitRepoFolder.exists() =======>>" + gitRepoFolder.exists());
if (gitRepoFolder.exists()) {
if (!gitRepoFolder.getAbsolutePath().endsWith(".git")) {
gitRepoFolder = new File(gitRepoFolder, ".git");
}
Repository db = Git.open(gitRepoFolder).getRepository();
db.incrementOpen();
return db;
} else {
throw new RepositoryNotFoundException("Unknown repository was requested by client " + name);
}
} catch (IOException e) {
throw new RepositoryNotFoundException(name, e);
}
}
});
}
My git war running under jettry server
http://localhost:8080/git.ctr-0.0.1-SNAPSHOT/
Now when i do git clone http://sohanb:welcome#localhost:8080/git.ctr-0.0.1-SNAPSHOT/portal/.git
The url i can see in logs/console,
http://localhost:8080/git.ctr-0.0.1-SNAPSHOT/portal/.git/
I don't know why use:pass missing from req url. Or it is not valid what i am trying to achieve.
Other suggestion to do this are most welcomed.
Please suggest.
A regex would be:
https?:\/\/(?<user>[^:]+):(?<password>[^#]+)
# look for http or https followed by ://
# capture everything up (but not including) a colon and capture it in a group called user
# match a colon
# capture everything up (but not including) an # and capture it in a group called password
See a demo here. It however somewhat depends on what you really want (working with the information in PHP, Python, the bash, etc.).
Since it is http:, you can use the java.net.URL:
URL url = new URL("http://sohanb:welcome#localhost:8080/git.ctr-0.0.1-SNAPSHOT/portal/.git");
String userInfo = url.getUserInfo(); // userInfo = "sohanb:welcome"
Check for null and then you can get what you want really easy:
String[] userInfoArray = userInfo.split(":");
String username = userInfoArray[0]; // sohanb
String password = userInfoArray[1]; // welcome

Servlet Filter as Security Proxy for Web Services

Good time.
Suppose there are 8 web-services in the one application. 5 of them require authorization (a client must to provide a JSESSIONID cookie and a corresponding session must not be invalidated), other 3 can be called without the jsessionid cookie. My naive solution is to write a servlet filter which intercepts requests and retrieve their pathInfos (all the services have the same url structure: /service/serviceSuffix). There is a enum which contains the serviceSuffix of each web service that requires authorization. When the request is retrieved the pathInfo is collected; if this pathInfo is contained in the enum and there is the corresponding valid session the request is sent ahead to the filter chain. Otherwise, an error is sent back to a client. After a while I've realized that it is needed to add the possibility to retrieve the wsdl and xsds for the concrete service. So that, two more check were added.
public class SecurityFilter implements Filter {
public static final String WSDL = "wsdl";
public static final String XSD = "xsd=";
/**
* Wittingly left empty
*/
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse)response;
String pathInfo = servletRequest.getPathInfo();
String queryString = servletRequest.getQueryString();
if (pathInfo != null && SecureWebServices.contains(pathInfo)) {
if (queryString != null && (queryString.equals(WSDL) || queryString.startsWith(XSD))) {
// wsdl or xsd is requested
chain.doFilter(request, response);
} else {
// a web service's method is called
HttpSession requestSession = servletRequest.getSession(false);
if (requestSession != null) { // the session is valid
chain.doFilter(request, response);
} else {
servletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
}
} else {
chain.doFilter(request, response);
}
}
/**
* Wittingly left empty
*/
public void destroy() {}
}
It seems that it is not very secure, because if the request's pathInfo is not in the enum, this request is passed on (just in case of some unexpected system calls).
Could you, please, suggest what to do, how to increase the security level. I want to build a configurable system (that is why I have the enum. It is possible just to add a path there to secure the web service and it is not required to duplicate the security code in the each web service). How to increase
Maybe I do not understand but.
jsessionid has nothink to do with security. you simply just get it.
Next I am not sure if you want authentication or authorization. The code as provided will not provide you with security features.
I suppose you are interested in authentication anyway. Security logic can be provided with standard web container features. Just send in authentication data in the header of request and you are done. web container can be configured to secure only selected resources (urls)