I am familiar with using Jersey to create RESTful webservice servers and clients, but due to class loading issues, I am trying to convert a Jersey client into CXF. I believe I want to use an HTTP-centric client but we don't use Spring. We need to use basic HTTP authentication. The user guide has this example:
WebClient client = WebClient.create("http:books", "username", "password", "classpath:/config/https.xml");
The first parameter isn't a URI string. Is it a format used by Spring? Can this method only be used to create WebClients using Spring?
The other way of doing authentication shown is to add a header string:
String authorizationHeader = "Basic " + org.apache.cxf.common.util.Base64Utility.encode("user:password".getBytes());
webClient.header("Authorization", authorizationHeader);
I am guessing that "user:password" should be substituted with the real values, but would appreciate confirmation.
This answer came from the CXF users mailing list.
The first example referenced above had a typo in it. It has been updated to:
WebClient client = WebClient.create("http://books", "username", "password", "classpath:/config/https.xml");
The fourth argument can be null if a Spring config file is (and therefore Spring) is not being used.
So, this worked for me:
private WebClient webClient;
public RESTfulClient(String url, String username, String password)
throws IllegalArgumentException
{
this.username = username;
this.password = password;
this.serviceURL = url;
if (username == null || password == null || serviceURL == null)
{
String msg = "username, password and serviceURL MUST be defined.";
log.error(msg);
throw new IllegalArgumentException(msg);
}
webClient = WebClient.create(this.serviceURL,
this.username,
this.password,
null); // Spring config file - we don't use this
}
Related
I'm using Spring Boot to login to an external program using its basic authentication. That authentication exists of giving username + password and use Base64 to encode the header. After this I can use a call + header (containing password and username) to retrieve data.
Is there a simple way in Spring Boot to temporary save that header? And after the user is done, he/she can simply remove that header?
Otherwise the user has to keep giving username+password for every call to the API.
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
String url = "url";
RestTemplate template = new RestTemplate();
HttpHeaders headers = createHeaders("mail", "password");
ResponseEntity<JsonSearchResponse> response = template.exchange(url, HttpMethod.GET,
new HttpEntity<JsonSearchResponse>(headers), JsonSearchResponse.class);
JsonSearchResponse obj = response.getBody();
SpringApplication.run(DemoApplication.class, args);
}
public static HttpHeaders createHeaders(String username, String password) {
return new HttpHeaders() {{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
String authHeader = "Basic " + new String(encodedAuth);
set("Authorization", authHeader);
}};
}
}
In the end I'm going to put this code in a different class. But just prototyping at the moment.
The application is going to be a web application. Using a database. I'm also going to use Thymeleaf.
All users use the same backend. As it is usually the case with web applications.
There is following way to configure the authentication header in Jersey API .
//Universal builder having different credentials for different schemes
HttpAuthenticationFeature feature = HttpAuthenticationFeature.universalBuilder()
.credentialsForBasic("username1", "password1")
.credentials("username2", "password2").build();
final Client client = ClientBuilder.newClient();
client.register(feature);
But not able to figure out how to pass extra parameter to authentication header for e.g. IntegatorKey, SendBehalfOf. those are specific REST service call.
In My Case to call REST service need to pass following parameter as part of authentication header.
Username
Password
IntegatorKey
SendBehalfOf
How should I achieve this using the Jersey API ?
You didn't provide enough information in your question. It's hard guessing what you are trying to achieve. You really should consider updating your question with more details.
Having a look at the superficial information you provided, I guess you are trying to access the DocuSign REST API. If so, you could create a ClientRequestFilter, as following:
public class DocuSignAuthenticator implements ClientRequestFilter {
private String user;
private String password;
private String integatorKey;
private String sendBehalfOf;
public DocuSignAuthenticator(String username, String password,
String integatorKey, String sendBehalfOf) {
this.username = username;
this.password = password;
this.integatorKey = integatorKey;
this.sendBehalfOf = sendBehalfOf;
}
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
requestContext.getHeaders().add(
"X-DocuSign-Authentication", getAuthenticationHeader());
}
private String getAuthenticationHeader() {
StringBuilder builder = new StringBuilder();
builder.append("<DocuSignCredentials>");
builder.append("<SendOnBehalfOf>");
builder.append(sendBehalfOf);
builder.append("</SendOnBehalfOf>");
builder.append("<Username>");
builder.append(username);
builder.append("</Username>");
builder.append("<Password>");
builder.append(password);
builder.append("</Password>");
builder.append("<IntegratorKey>");
builder.append(integatorKey);
builder.append("</IntegratorKey>");
builder.append("</DocuSignCredentials>");
return builder.toString();
}
}
And register it when creating a Client instance:
Client client = ClientBuilder.newClient().register(
new DocuSignAuthenticator(username, password, integatorKey, sendBehalfOf));
This is a follow-up question to the one I asked yesterday.
The log-in page is supposed to redirect to main page after correct username and password input, with server side returning an empty string (""). If either is incorrect, server side code returns "Username or Password are incorrect".
The page functionality worked well but when I was testing using my client side code using a correct pair of username and password, it returns "Username or Password are incorrect", with response returning 200OK.
Below is my client side code:
public static void main(String[] args){
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target("http://localhost:8080
/qa-automation-console").path("authenticate");
Form form = new Form();
form.param("username", "username");
form.param("password", "password");
Response response = target.request().post(Entity.form(form));
//The response was 200OK.
System.out.println(response.readEntity(String.class));
}
Instead of other problems including HTML and Web.xml dependency, now I suspect the client code I wrote was not correct and when the request is sent it does not contain the correct username and password. The server side code is below:
#POST
#Produces("text/plain")
#Path("authenticate")
public String authenticate(#Context HttpServletRequest req, #QueryParam("username")
String username, #QueryParam("password") String password)
throws Exception {
Environments environments = new DefaultConfigurationBuilder().build();
final ALMProfile profile = new ALMProfile();
profile.setUrl(environments.getAutomation().getAlmProfile().getUrl());
profile.setUsername(username);
if ( !Strings.isNullOrEmpty(password) ) {
String encryptedPassword = EncryptionUtils.encrypt(password);
profile.setPassword(encryptedPassword);
}
try (ALMConnection connection = new ALMConnection(profile);) {
if (connection.getOtaConnector().connected()) {
req.getSession(true).setAttribute("username", username);
req.getSession(true).setAttribute("password", profile.getPassword());
return "";
}
} catch (Exception e) {
e.printStackTrace();
return "Username or Password are incorrect";
}
return "Username or Password are incorrect";
}
Can someone point out if the client code submits the correct request?
First of all, you probably need to check what's in your stack trace. And the value of username and password. I suspect them to be null.
Secondly, I think the problem is coming from the #QueryParam annotation.
You must use instead #FormParam
You use QueryParam when your url contain params as:
www.test.com/test?username=test
When you're sending data in a Form, you must use the annotation #FormParam
I'm trying to write a simple smoke test for a web application.
The application normally uses form based authentication, but accepts basic auth as well, but since the default is form based authentication, it never sends an authentication required, but instead just sends the login form.
In the test I try to send the basic auth header using
WebClient webClient = new WebClient();
DefaultCredentialsProvider creds = new DefaultCredentialsProvider();
// Set some example credentials
creds.addCredentials("usr", "pwd");
// And now add the provider to the webClient instance
webClient.setCredentialsProvider(creds);
webClient.getPage("<some url>")
I also tried stuffing the credentials in a WebRequest object and passing that to the webClient.getPage method.
But on the server I don't get an authentication header. I suspect the WebClient only sends the authentication header if it get explicitly asked for it by the server, which never happens.
So the question is how can I make the WebClient send the Authentication header on every request, including the first one?
This might help:
WebClient.addRequestHeader(String name, String value)
More specific one can create an authentication header like this
private static void setCredentials(WebClient webClient)
{
String username = "user";
String password = "password";
String base64encodedUsernameAndPassword = base64Encode(username + ":" + password);
webClient.addRequestHeader("Authorization", "Basic " + base64encodedUsernameAndPassword);
}
private static String base64Encode(String stringToEncode)
{
return DatatypeConverter.printBase64Binary(stringToEncode.getBytes());
}
I am Writting a Restful webservice with Jersey, this is the sample code:
#GET
#Produce(MediaType.APPLICATION_JSON)
public String findItems(){
...
}
and the url of findItem is localhost:8080/items
the method should verify the http authentication info(digest or basic) of this url before excutes, how to access authentication from the a url request first?
I would not put this in the controller itself, but in a com.sun.jersey.spi.container.ContainerRequestFilter around the resource classes you wish to protect, but should give you the basic idea.
#Context
private HttpServletRequest request;
#GET
#Produce(MediaType.APPLICATION_JSON)
public String findItems(){
String auth = request.getHeader("authorization");
if (auth != null) {
String basic_prefix = "Basic ";
if (auth.startsWith(basic_prefix)) {
String auth_data = new String(Base64.decode(auth.substring(basic_prefix.length())));
String [] user_and_key = auth_data.split(":", 2);
// user and password available here
} else {
// reject access
}
} else {
// reject access
}
}
Usually the authentication is handled by the container, you just have to add the corresponding constraint to web.xml to indicate what Uris should be protected and what kind of auth is required. Then in jersey you can get the roles and principal info from the SecurityContext you can inject to your resource.