Getting the OAUTH2 Token - java

I'm trying to retrieve a OAUTH2 token from our IDM server - I've tried several flavors of rudimentary examples, but all of them return a 200 status with no code included. I can do it with no trouble via postman, using a header of:
Content-Type application/x-www-form-urlencoded
... and sending the client_id, redirect_uri and code parameters. I get something back that looks like this:
{
"access_token": "abcd...",
"token_type": "bearer",
"expires_in": 3600
}
Here's the super rudimentary code intended to do no more than see if I can grab the token (at this point):
public class Service {
public String getToken() {
String client_id = "f2e8...";
String redirect_uri = "https://mysite/";
String code = "AAAAAA...";
form = new Form();
form.param("client_id", client_id);
form.param("code", code);
form.param("redirect_uri", redirect_uri);
JerseyClientBuilder jerseyClientBuilder = new JerseyClientBuilder();
JerseyWebTarget jerseyWebTarget =
jerseyClientBuilder.build().target("https://token-source-site/");
Response response = jerseyWebTarget.request().post(Entity.form(form));
return response.toString();
}
}
But all I get back is:
InboundJaxrsResponse{context=ClientResponse{method=POST,
uri=https://token-source-site/, status=200, reason=OK}}
Any thoughts on what Postman might be doing that my code isn't?

It's not going to show to the response body when you just call toString() on the Response. You need to extract the body from it by calling Response#readEntity.
But even trying to extract it to a String, you have the problem of still having to parse the string. Best thing to do is to create a POJO for the token response
public class AccessTokenResponse {
#JsonProperty("access_token")
private String accessToken;
#JsonProperty("token_type")
private String tokenType;
#JsonProperty("expires_in")
private long expiresIn;
// getters and setters
}
Then you can do
Response response = jerseyWebTarget.request().post(Entity.form(form));
return response.readEntity(AccessTokenResponse.class);
Make the method return AccessTokenResponse, so the client has access to the other properties also.
For this to work, you will need to have the Jackson provider dependency
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>

Related

OpenFeign not decoding response

#FeignClient(name = "Authorization-API", url = "https://www.reddit.com/api/v1")
public interface AuthorizationApi {
#RequestMapping(method = RequestMethod.POST, value = "/access_token")
Token getToken(#PathVariable("grant_type") String grantType,
#PathVariable String code,
#PathVariable("redirect_uri") String redirectUrl,
#RequestHeader(name = "Authorization") String authorizationHeader,
#RequestHeader("User-agent") String agent
);
}
Call:
Token token = authorizationApi.getToken(
"authorization_code",
code,
REDIRECT_URI,
getAuthorizationCredentials(),
"porymol");
System.out.println(token.access_token()); //returns null
Token record:
public record Token(String access_token, String token_type, Long expires_in, String scope, String refresh_token) {
}
When I make request from Postman I get this response:
{
"access_token": "token",
"token_type": "bearer",
"expires_in": 86400,
"refresh_token": "token",
"scope": "read"
}
Trying to get any value from Token returns null
Java 17, Spring boot 3
Any idea what's going wrong here?
First of all you have declared two path variables which dont show up the path:
#PathVariable String code and #PathVariable("redirect_uri") String redirectUrl.
Overall it looks like you are trying to request an oauth access token which requires an request of content type application/x-www-form-urlencoded.
Maybee this helps: How to POST form-url-encoded data with Spring Cloud Feign

How to send data into Elastic Cloud from Java?

I want to insert (index) some data into Elastic Search running in Elastic Cloud in a Java application.
To do so, I wrote the following piece of code:
void sendStuffToElasticSearch() {
RestHighLevelClient client = null;
try {
client = new RestHighLevelClient(
RestClient.builder(CLOUD_ID)
);
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
builder.addHeader("Authorization", String.format("ApiKey %s",
API_KEY));
final RequestOptions requestOptions = builder.build();
IndexRequest request = new IndexRequest("posts");
request.id("1");
String jsonString = "{" +
"\"user\":\"kimchy\"," +
"\"postDate\":\"2013-01-30\"," +
"\"message\":\"trying out Elasticsearch\"" +
"}";
request.source(jsonString, XContentType.JSON);
IndexResponse indexResponse = client.index(request, requestOptions);
System.out.println("indexResponse");
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(client);
}
}
API_KEY is the key I generated according to this tutorial which also says I need to send it in the Authorization header in the following format: Authorization: ApiKey $EC_API_KEY.
When I run the above code, I am getting the following error:
org.elasticsearch.client.ResponseException: method [PUT], host [https://XXXXXXXXXX:9243], URI [/posts/_doc/1?timeout=1m], status line [HTTP/1.1 401 Unauthorized]
{"error":{"root_cause":[{"type":"security_exception","reason":"missing authentication credentials for REST request [/posts/_doc/1?timeout=1m]","header":{"WWW-Authenticate":["Basic realm=\"security\" charset=\"UTF-8\"","Bearer realm=\"security\"","ApiKey"]}}],"type":"security_exception","reason":"missing authentication credentials for REST request [/posts/_doc/1?timeout=1m]","header":{"WWW-Authenticate":["Basic realm=\"security\" charset=\"UTF-8\"","Bearer realm=\"security\"","ApiKey"]}},"status":401}
at org.elasticsearch.client.RestClient.convertResponse(RestClient.java:326)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:296)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:270)
at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1621)
... 30 more
How can fix this, i. e. provide all authentication-related data in the way Elastic Cloud expects them?
I am using following libraries:
<properties>
[...]
<elastic-search-client.version>7.11.1</elastic-search-client.version>
</properties>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>${elastic-search-client.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elastic-search-client.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elastic-search-client.version}</version>
</dependency>
Update 1: Base64-encoding of the API key as suggested here (see code below) did not help.
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
builder.addHeader("Authorization", String.format("ApiKey %s",
Base64.getEncoder().encodeToString(API_KEY.getBytes(StandardCharsets.UTF_8))));
final RequestOptions requestOptions = builder.build();
Update 2: Changing the way I create the client, did not help, either (see below).
Header[] defaultHeaders =
new Header[]{new BasicHeader("Authorization",
String.format("ApiKey %s",API_KEY))};
final RestClientBuilder builder1 = RestClient.builder(CLOUD_ID);
builder1.setDefaultHeaders(defaultHeaders);
client = new RestHighLevelClient(
builder1
);
Update 3: I changed the supplied API key to
public static final String BASE64_API_KEY = Base64.getEncoder().encodeToString(String.format("%s:%s", ID, KEY).getBytes());
as suggested by Ricardo Ferreira.
Now I am getting a different error:
org.elasticsearch.client.ResponseException: method [PUT], host [XXXXXXXXXXXXXXXX], URI [/posts/_doc/1?timeout=1m], status line [HTTP/1.1 403 Forbidden]
{"error":{"root_cause":[{"type":"security_exception","reason":"action [indices:admin/auto_create] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"}],"type":"security_exception","reason":"action [indices:admin/auto_create] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"},"status":403}
at org.elasticsearch.client.RestClient.convertResponse(RestClient.java:326)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:296)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:270)
at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1621)
... 30 more
Update 4:
After I created the index in question, the error message changed to this:
org.elasticsearch.client.ResponseException: method [PUT], host [XXXXXXXXXXXXXXXX], URI [/camunda-1/_doc/1?timeout=1m], status line [HTTP/1.1 403 Forbidden]
{"error":{"root_cause":[{"type":"security_exception","reason":"action [indices:data/write/bulk[s]] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"}],"type":"security_exception","reason":"action [indices:data/write/bulk[s]] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"},"status":403}
It's not working because you are using the wrong API Key.
But don't worry: these things happen a lot. It certainly happened to me.
The API Key that you are creating is for you to issue REST requests against Elasticsearch Service — which is the entity that governs your Elasticsearch and Kibana clusters.
To make it work, you need to create an API Key from Elasticsearch specifically. To create one, go to the Dev Tools Console and issue the following request:
POST _security/api_key
{
"name": "my-api-key",
"expiration": "7d",
"role_descriptors": {
"custom-role": {
"cluster": ["all"],
"index": [
{
"names": [
"index-1",
"index-2"
],
"privileges": ["all"]
}
]
}
}
}
If executed successfully, you will get a response like this:
{
"id" : "liKs_XcBrNsSAgwboCN9",
"name" : "my-api-key",
"expiration" : 1615473484899,
"api_key" : "NC3ZeIb_SGWjGJRZVoOf2g"
}
Take note of the fields id and api_key. You are going to need them to create the authorization header:
String apiKey = String.format("%s:%s", id, api_key);
apiKey = Base64.getEncoder().encodeToString(apiKey.getBytes());
String authorization = String.format("ApiKey %s", apiKey);
After this just use the authorization in your Java code:
builder.addHeader("Authorization", authorization);

How to make a POST call using Scribe and fetch data having OAuth 1.0 Authentication in Java?

I have a requirement to make a post-call to a URL which has OAuth 1.0 authentication. I am pretty new to all these. From my research, I got to know about Scribe in Java, but I can find only Get calls using Scribe. I already have consumerKey and consumerSecret key for OAuth 1.0 authentication. Are there any suggestions on how to achieve this successfully.
With postman I am able to fetch the data successfully, but I want to achieve it using Java.
I have tried something like this
I tried this way
public String getSmartCommPDF(#RequestBody Model model) throws IOException {
OAuthService service = new ServiceBuilder().provider(ModelAPI.class).apiKey(consumerKey)
.apiSecret(consumerSecret).build();
OAuthRequest request = new OAuthRequest(Verb.POST, url);
ObjectMapper mapper = new ObjectMapper();
request.addHeader("Content-Type", "application/json;charset=UTF-8");
request.addPayload(mapper.writeValueAsString(model));
Token accessToken = new Token("", ""); // not required for context.io
service.signRequest(accessToken, request);
Response response = request.send();
System.out.println("Response = " + response.getBody());
return "Success";
}
This is my ModelAPI class
public class ModelAPI extends DefaultApi10a {
#Override
public String getRequestTokenEndpoint() {
return "https://domain/one/oauth1/api/v6/job";
}
#Override
public String getAccessTokenEndpoint() {
return "https://domain/one/oauth1/api/v6/job";
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return "https://domain/one/oauth1/api/v6/job";
}
}
This part of code is not throwing any error but, the response body is empty. Where I am going wrong, any one has any idea?
Thank you.
The data was coming back in the input stream. So, I used
response.getStream();
and write it to a file and use it.

Java REST Client - Bad Request (400) - The request could not be understood by the server due to malformed syntax

I am trying to create a Java REST client to consume an api. When I try call it from my Java client, I get:
Bad Request (400) - The request could not be understood by the server
due to malformed syntax
Problem
My Rest client is not complete. I think the jwt token is being set correctly in the header, I just think that the cr.post() call is not correct. Perhaps the MediaType is wrong?
Question
How do I change the Rest client to call the server and get the expected response? Also how do I convert the response to a ApprovalResponse ?
Rest client (Java 7):
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
private static String callSubmitApprovals(String endpointUrl, ApprovalRequest approvalRequest, String token) {
System.out.println(endpointUrl);
try {
ClientResource cr = new ClientResource(endpointUrl);
ChallengeResponse challengeResponse = new ChallengeResponse(ChallengeScheme.HTTP_OAUTH_BEARER);
challengeResponse.setRawValue(token);
cr.setChallengeResponse(challengeResponse);
Representation response = cr.post(approvalRequest, MediaType.APPLICATION_JAVA);
System.out.println(response);
//ApprovalResponse approvalResponse = response;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
RESTful Api (Server) (Spring & Java 14):
#RestController
public class ApprovalSubmitResource {
#PostMapping("/rest/approvals-submit")
public ApprovalResponse submit(#RequestHeader(name="Authorization") String token, #RequestBody ApprovalRequest approvalRequest) {
System.out.println(approvalRequest);
ApprovalResponse approvalResponse = new ApprovalResponse();
approvalResponse.setApprovalId("Test approvalResponse from micro service");
return approvalResponse;
}
}
POM:
<dependency>
<groupId>org.restlet.jee</groupId>
<artifactId>org.restlet</artifactId>
<version>2.3.1</version>
</dependency>

Restful Webservice string response

I have an endpoint where it supposes to sends a string as a response. My question is do I need to use to response Entity to send string response or just return the string to the consumer?
#GetMapping(value = "/word")
public String getWord() {
String response = "webservice";
return response;
}
Second approach:
#GetMapping(value = "/word", produces ={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> getWord() {
String response = "webservice";
return new ResponseEntity<>(response, HttpStatus.OK);
}
What is the correct approach to send just a string or use response entity?
What is the correct approach to send just a string or use response entity?
The Spring MVC documentation lists a number of types that can be returned from controller methods.
As I previously answered here and here, ResponseEntity<T> represents the entire HTTP response. Besides the body, its API allows you to set headers and a status code to the response.
Returning just a bean instance or a string is fine but doesn't give you much flexibility: In the future, if you need to add a header to the response or modify the status code, for example, you need to change the method return type.

Categories

Resources