I'm trying to implement basic HTTP authentication using Restlet 2.1, and I just can't get it to work .. ! I'm using a ChallengeAuthenticator to setup Basic HTTP authentication. I have just one URI \test, for which I'm trying to get authentication working.
I build my code, then run it as a Web Application and then browse to http://localhost:8888/test to see if I get a prompt for a username/password, but I don't get any. I just get a blank screen.
Also when I browse to http://localhost:8888/test, I get the following written in Eclipse's Console:
WARNING: A response with a 200 (Ok) status should have an entity. Make sure that resource "http://localhost:8888/test" returns one or sets the status to 204 (No content).
When when I browse to http://user:password#localhost:8888/test, the result is exactly the same.
The HTTP headers (from Chrome) are as follows:
Request:
GET /test HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,ms;q=0.6
Response (no mention of Basic authentication):
HTTP/1.1 200 OK
Date: Fri, 13 Jun 2014 11:21:05 GMT
Accept-Ranges: bytes
Server: Development/1.0
Content-Length: 0
Cache-Control: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Here is the Java code:
package com.poc.hw7;
import org.restlet.*;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Cookie;
import org.restlet.data.MediaType;
import org.restlet.routing.Router;
import org.restlet.security.*;
import org.restlet.util.Series;
public class AuthTestApp extends Application {
private ChallengeAuthenticator authenticator;
private ChallengeAuthenticator createAuthenticator() {
Context context = getContext();
boolean optional = false;
ChallengeScheme challengeScheme = ChallengeScheme.HTTP_BASIC;
String realm = "Example site";
MapVerifier verifier = new MapVerifier();
verifier.getLocalSecrets().put("user", "password".toCharArray());
ChallengeAuthenticator auth = new ChallengeAuthenticator(context, optional, challengeScheme, realm, verifier) {
#Override
protected boolean authenticate(Request request, Response response) {
if (request.getChallengeResponse() == null) {
return false;
} else {
return super.authenticate(request, response);
}
}
};
return auth;
}
#Override
public Restlet createInboundRoot() {
this.authenticator = createAuthenticator();
Restlet hw_restlet = new Restlet(getContext())
{
public void handle(Request request, Response response)
{
String message = "Hello World!";
response.setEntity(message,MediaType.TEXT_PLAIN);
}
};
Router router = new Router();
router.attach("/test", hw_restlet);
authenticator.setNext(router);
return authenticator;
}
public boolean authenticate(Request request, Response response) {
if (!request.getClientInfo().isAuthenticated()) {
authenticator.challenge(response, false);
return false;
}
return true;
}
}
Here is the web.xml file:
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>Restlet URI Rewrite</display-name>
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.application</param-name>
<param-value>com.poc.hw7.AuthTestApp</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Can someone please tell me how to get basic HTTP authentication working ?
Your response was a 200 code, which means your server never asked for one. You would need to send a 401 response. For most web browsers, this will automatically pop up the basic-auth box for a username and password.
As for why this is happening... it's hard to say. restlet looks very... bad. There are easier frameworks to work with, where you can just annotate a function to listen to a certain URI and/or request method.
Related
This question already has an answer here:
CORS Error: “requests are only supported for protocol schemes: http…” etc
(1 answer)
Closed 3 years ago.
I am attempting to connect my angular app to my new Spring Boot 2 controller. I start everything up and I get:
Access to XMLHttpRequest at 'localhost:8093/restapi/setup' from origin 'http://localhost:4200' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
Followed by:
ERROR HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "localhost:8093/restapi/setup", ok: false, …}
So this is CORS, right? When I hit localhost:8093/restapi/setup from postman, I get a valid response, as you'd expect.
So I do some research and especially I find this: No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API
I finally find this article here:
https://chariotsolutions.com/blog/post/angular-2-spring-boot-jwt-cors_part1/
And that leads me to the following code:
#Configuration
public class ManageConfiguration {
private static final Logger LOGGER = LogManager.getLogger(ManageConfiguration.class);
#Bean
public CorsFilter corsFilter() {
LOGGER.debug("Configuring CORS");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("GET");
config.addAllowedMethod("POST");
config.addAllowedMethod("PUT");
config.addAllowedMethod("DELETE");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
So I think this is straightforward and now try again and I get:
Access to XMLHttpRequest at 'localhost:8093/restapi/setup' from origin 'http://localhost:4200' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
Followed by:
ERROR HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "localhost:8093/restapi/setup", ok: false, …}
So it doesn't appear to make any difference whatsoever.
Checked and it's running on the right port:
2019-02-27 14:23:21.261 INFO 9814 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8093 (http) with context path ''
Made sure it included my CORS bean:
2019-02-27 14:23:19.608 DEBUG 9814 --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Creating shared instance of singleton bean 'corsFilter'
...
o.springframework.web.filter.CorsFilter : Filter 'corsFilter' configured for use
Per How can you debug a CORS request with cURL?, I did the following curl request to see my pre-flight stuff.
$ curl -H "Origin: http://example.com" --verbose http://localhost:8093/restapi/setup
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8093 (#0)
> GET /restapi/setup HTTP/1.1
> Host: localhost:8093
> User-Agent: curl/7.61.0
> Accept: */*
> Origin: http://example.com
>
< HTTP/1.1 200
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Access-Control-Allow-Origin: http://example.com
< Access-Control-Allow-Credentials: true
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 27 Feb 2019 21:38:28 GMT
<
* Connection #0 to host localhost left intact
{"issueType":["bug","epic","subTask","task","story"]}
Been scratching my head for a day about what to try next and can't come up with anything. Suggestions?
i think you're sending an ajax request without http:// protocol prefix in your request URL, try hitting http://localhost:8093/restapi/setup from ajax.
Add this WebSecurityConfigurerAdapter in your code
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
}
}
Also add the following WebMvcConfigurer
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class WebMvcConfigurerImpl implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
At last add this annotation on top of your rest controller class : #CrossOrigin.
#CrossOrigin
public class RestController {
// Your methods
}
If you have a filter, you can add the following attributes to the response, if you don't have, you can use this one.
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import org.springframework.web.filter.OncePerRequestFilter;
#Service
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
response.setHeader("Access-Control-Expose-Headers", "Content-Length, Authorization");
filterChain.doFilter(request, response);
}
}
#Configuration
public class CorsConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
.allowedHeaders("*");
}
};
}
}
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
Please check the tutorial here https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
Got a websocket - see the authToken in the Cookie, in Java Spring how do you validate this authToken? I understand this authToken is passed down from the http layer to the websocket so I'm trying to validate that the websocket is being opened by our app and not by some other source.
Headers for Websocket:
GET ws://localhost:9999/somePath/websocket HTTP/1.1
Host: localhost:9999
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Upgrade: websocket
Origin: http://localhost
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: authToken=elFKMk5TckR0ZUNvdnZySUJxc2ZMdz09OklEZENrRFRySkp0U0ltVFdKU1RIZVE9PQ
Sec-WebSocket-Key: e//VDAjHSRjE810tCbIEyw==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Protocol: v10.stomp, v11.stomp, v12.stomp
I would like to validate that authToken in the HttpHandshakeInterceptor.beforeHandshake
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer
registry.addEndpoint(stompEndPoint).addInterceptors(new HttpHandshakeInterceptor()).setAllowedOrigins("*").withSockJS();
public class HttpHandshakeInterceptor implements HandshakeInterceptor
Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession();
attributes.put("sessionId", session.getId());
// validate token logic
}
return true;
}
I've tried to implement a REST service with RESTEasy in a GWT project, but when I get into the respective URI the application returns:
Grave: failed to execute
javax.ws.rs.NotFoundException: Could not find resource for full path: http://127.0.0.1:8888/api/matches
at org.jboss.resteasy.core.registry.ClassNode.match(ClassNode.java:73)
at org.jboss.resteasy.core.registry.RootClassNode.match(RootClassNode.java:48)
at org.jboss.resteasy.core.ResourceMethodRegistry.getResourceInvoker(ResourceMethodRegistry.java:444)
at org.jboss.resteasy.core.SynchronousDispatcher.getInvoker(SynchronousDispatcher.java:234)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:171)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
My web.xml is:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- All REST resources will be prefixed by /api -->
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/api</param-value>
</context-param>
<!-- Servlets -->
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>eii.api.MatchApplication</param-value>
</init-param>
</servlet>
<!-- Servlet mappings -->
<!-- All calls to /api/xxx will be sent to the reasy servlet -->
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
The implementation of Application:
public class MatchApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public MatchApplication() {
singletons.add(new MatchServiceImpl());
}
#Override
public Set<Class<?>> getClasses() {
return classes;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
And here's the class that provide the REST service:
/* Imports */
...
#Path("/matches")
public class MatchResource {
private static MatchResource _instance = null;
private MatchRepository repository;
public MatchResource() {
repository = new MapMatchRepository();
}
public static MatchResource getInstance() {
if (_instance == null)
_instance = new MatchResource();
return _instance;
}
#GET
#Path("/{id}")
#Produces("application/json")
public Match getMatch(#PathParam("id") int id) {
return repository.getMatch(id);
}
#GET
#Produces("application/json")
public Matches getMatchesCurrentRound() {
return repository.getMatchesCurrentRound();
}
...
}
What I want is to return a JSON file when getting into, for example: http://127.0.0.1:8888/api/matches
Does anyone know what I'm doing wrong?
Edit:
If I access to http://127.0.0.1:8888/api/ or http://127.0.0.1:8888/api/* (where * is whatever you want to write), the browser shows nothing. However, if I access to http://127.0.0.1:8888/oqiwn (where oqiwn is a random string) the browser shows a Error 404.
Also, I tried the RESTClient addon and these are the answers that returns:
With http://127.0.0.1:8888/api/ or http://127.0.0.1:8888/api/*
Status Code: 404 Not Found
Cache-Control: no-cache
Content-Length: 0
Date: Sun, 10 Nov 2013 22:59:57 GMT
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Server: Development/1.0
And with http://127.0.0.1:8888/oqiwn
Status Code: 404 Not Found
Cache-Control: no-cache
Content-Length: 83
Content-Type: text/html; charset=iso-8859-1
Date: Sun, 10 Nov 2013 22:59:05 GMT
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Server: Development/1.0
Note that Content-Type: text/html; charset=iso-8859-1 is not in the first one.
You added your resource using a method named getMatches(), which Resteasy knows nothing about. You need to override the getSingletons() method of Application and return your root resources from there as shown below.
Documentation Here
Example:
public class MatchApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public MatchApplication() {
singletons.add(new MatchServiceImpl());
}
#Override
public Set<Class<?>> getClasses() {
return classes;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
First, I think your MatchApplication class should be annotated with #ApplicationPath("/api"). I'm sorry if that's already done.
Then, depending on your RESTEasy version, it will scan automatically for classes that are providers or resources, so you don't need to give to implement anything on your MatchApplication for now. Just extend Application and you are done.
If you can update your web-app to use servlet 3.0, you don't need to put any kind of configuration into your web.xml.
Read more on the RESTEasy documentation.
This works for all my services.
This is a runtime exception indicating a resource requested by a client was not found on the server.
Add below entry into your web.xml :
<context-param>
<param-name>resteasy.resources</param-name>
<param-value>com.org.abc.xyz.MainClassName</param-value>
</context-param>
You can specify fully qualified name of your JAX-RS resource class name you want to register.
If you have multiple classes entries, use comma delimiter.
Trying to download a file am getting an error, i couldn't able to download the file from Drive.
Here is the code i used
private static InputStream downloadFile(String token, File file) {
Drive service = getDriveService(getCredential(token));
if (file.getDownloadUrl() != null && file.getDownloadUrl().length() > 0) {
try {
HttpResponse resp =
service.getRequestFactory().buildGetRequest(new GenericUrl(file.getDownloadUrl()))
.execute();
return resp.getContent();
} catch (IOException e) {
// An error occurred.
e.printStackTrace();
return null;
}
} else {
// The file doesn't have any content stored on Drive.
return null;
}
}
and i'm getting this error
GET /a/thotz.net/uc?id=xxxxx&export=download HTTP/1.1
Host: docs.google.com
Content-length: 0
Authorization: OAuth ya29.AHES6ZTruwaMm_SHZAb9LFMCbxiJ85vaDccbil-h4enw
HTTP/1.1 401 Unauthorized
Content-length: 147
X-xss-protection: 1; mode=block
X-content-type-options: nosniff
X-google-cache-control: remote-fetch
-content-encoding: gzip
Server: GSE
Reason: Unauthorized
Via: HTTP/1.1 GWA
X-chromium-appcache-fallback-override: disallow-fallback
Cache-control: private, max-age=0
Date: Thu, 25 Apr 2013 19:54:12 GMT
X-frame-options: SAMEORIGIN
Content-type: text/html; charset=UTF-8
Expires: Thu, 25 Apr 2013 19:54:12 GMT
<HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
i test the token in other request and is it work, so don't know why when i try to download a file show a 401 error.
I had similar problem using PHP library - turns out you need to make your request with authentication - 401 error means you are not authenticated.
I'm using a SOAPHandler and here's my getHeaders method at the client side:
#Override
public Set<QName> getHeaders() {
String uri = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
QName security_hdr = new QName(uri, "Security", "wsse");
HashSet<QName> headers = new HashSet<QName>();
headers.add(security_hdr);
System.out.println("Headers: " + headers);
return headers;
}
The SystemOut in the above line produces this code, so definitely I did return something from my method:
Headers: [{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security]
However, when trying to capture the request in TCPMon, I don't see the header at all.
POST /ws/server HTTP/1.1
Content-type: text/xml;charset="utf-8"
Soapaction: ""
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: JAX-WS RI 2.1.6 in JDK 6
Host: 127.0.0.1:4027
Connection: keep-alive
Content-Length: 170
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body><ns2:getServerName xmlns:ns2="http://ws.ronixus.com/"/></S:Body>
</S:Envelope>
Any idea what I'm missing here? I've already commented out code from the other callback method handleMessage to make sure there's nothing overwriting the header.
Maybe try this in handleMessage, just to confirm?
SOAPHeader soapHeader = soapEnv.getHeader();
Iterator headers = soapHeader.extractAllHeaderElements();
while(headers.hasNext() ){
SOAPHeaderElement headerElement = (SOAPHeaderElement) headers.next();
Name name = headerElement.getElementName();
System.out.println(name)
}