IBM Cloud Object Storage Java Client - IllegalArgument exception - ibm-cloud

I'm following sample provided here https://console.bluemix.net/docs/services/cloud-object-storage/libraries/java.html#java
Created the following code:
SDKGlobalConfiguration.IAM_ENDPOINT = "https://iam.bluemix.net/oidc/token";
String bucketName = "mybucket_name";
String api_key = "api_key_taken_fro_the_service_credential_json";
String service_instance_id = "service_id_taken_from_the_bucket_policies_page";
String endpoint_url = "http://s3.mel01.objectstorage.softlayer.net";
String location = "mel01";
System.out.println("Current time: " + new Timestamp(System.currentTimeMillis()).toString());
_cos = createClient(api_key, service_instance_id, endpoint_url, location);
listObjects(bucketName, _cos);
listBuckets(_cos);
the listObjects and listBuckets are exact c&p from that referred page.
I'm getting Invalid argument exception, as follows:
Listing objects in bucket mybucket_name
[INFO ] FFDC1015I: An FFDC Incident has been created: "com.ibm.cloud.objectstorage.services.s3.model.AmazonS3Exception: Invalid Argument (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument; Request ID: 3bb36c4c-8de4-4f39-98f4-a1bfd3aa8972), S3 Extended Request ID: null com.ibm.ws.webcontainer.servlet.ServletWrapper.init 181" at ffdc_18.04.12_13.02.15.0.log
[ERROR ] SRVE0271E: Uncaught init() exception created by servlet [gas.servlet.BlmxS3Servlet] in application [s3]: com.ibm.cloud.objectstorage.services.s3.model.AmazonS3Exception: Invalid Argument (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument; Request ID: 3bb36c4c-8de4-4f39-98f4-a1bfd3aa8972), S3 Extended Request ID: null
at com.ibm.cloud.objectstorage.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1588)
at com.ibm.cloud.objectstorage.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1258)
at com.ibm.cloud.objectstorage.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1030)
at com.ibm.cloud.objectstorage.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:742)
at com.ibm.cloud.objectstorage.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:716)
at com.ibm.cloud.objectstorage.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:699)
at com.ibm.cloud.objectstorage.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667)
at com.ibm.cloud.objectstorage.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649)
at com.ibm.cloud.objectstorage.http.AmazonHttpClient.execute(AmazonHttpClient.java:513)
at com.ibm.cloud.objectstorage.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3635)
at com.ibm.cloud.objectstorage.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3582)
at com.ibm.cloud.objectstorage.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3576)
at com.ibm.cloud.objectstorage.services.s3.AmazonS3Client.listObjects(AmazonS3Client.java:761)
at gas.servlet.BlmxS3Servlet.listObjects(BlmxS3Servlet.java:94)
at gas.servlet.BlmxS3Servlet.init(BlmxS3Servlet.java:63)
at javax.servlet.GenericServlet.init(GenericServlet.java:244)
at [internal classes]
What argument might be invalid? No clue from the log nor ffdc.
UPDATE
The bucket name is correct, otherwise I'm getting:
[ERROR ] SRVE0271E: Uncaught init() exception created by servlet [gas.servlet.BlmxS3Servlet] in application [s3]: com.ibm.cloud.objectstorage.services.s3.model.AmazonS3Exception: The specified bucket does not exist. (Service: Amazon S3; Status Code: 404; Error Code: NoSuchBucket; Request ID: bf299e50-1aac-4af7-89df-188eb4b7c60f), S3 Extended Request ID: null

your endpoint_url should be over https instead of http

There were several issues during configuring this:
1) You need to create credential with additional properties of {"HMAC":true}
2) For the configuration use:
apikey - apikey entry from the credential
service_instance_id - this is a bit misleading - as it is your Object servcie name, not id - in my case it was string Cloud Object Storage-abc
endpoint_url - bucket endpoint - in my case http://s3.mel01.objectstorage.softlayer.net - make sure that it is https and that you imported certificates to your truststore.
Then is should work.
Listing buckets is not working for me still due to "Access Denied", so I have to check the permissions for the service ID.

Related

RESTful client in Unity - validation error

I have a RESTful server created with ASP.Net and am trying to connect to it with the use of a RESTful client from Unity. GET works perfectly, however I am getting a validation error when sending a POST request. At the same time both GET and POST work when sending requests from Postman.
My Server:
[HttpPost]
public IActionResult Create(User user){
Console.WriteLine("***POST***");
Console.WriteLine(user.Id+", "+user.sex+", "+user.age);
if(!ModelState.IsValid)
return BadRequest(ModelState);
_context.Users.Add(user);
_context.SaveChanges();
return CreatedAtRoute("GetUser", new { id = user.Id }, user);
}
My client:
IEnumerator PostRequest(string uri, User user){
string u = JsonUtility.ToJson(user);
Debug.Log(u);
using (UnityWebRequest webRequest = UnityWebRequest.Post(uri, u)){
webRequest.SetRequestHeader("Content-Type","application/json");
yield return webRequest.SendWebRequest();
string[] pages = uri.Split('/');
int page = pages.Length - 1;
if (webRequest.isNetworkError || webRequest.isHttpError){
Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text);
}
else{
Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text);
}
}
}
I was trying both with the Json conversion and writing the string on my own, also with the WWWForm, but the error stays.
The error says that it's an unknown HTTP error. When printing the returned text it says:
"One or more validation errors occurred.","status":400,"traceId":"|b95d39b7-4b773429a8f72b3c.","errors":{"$":["'%' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0."]}}
On the server side it recognizes the correct method and controller, however, it doesn't even get to the first line of the method (Console.WriteLine). Then it says: "Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.ValidationProblemDetails'".
Here're all of the server side messages:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 POST http://localhost:5001/user application/json 53
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'TheNewestDbConnect.Controllers.UserController.Create (TheNewestDbConnect)'
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3]
Route matched with {action = "Create", controller = "User"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Create(TheNewestDbConnect.Data.Entities.User) on controller TheNewestDbConnect.Controllers.UserController (TheNewestDbConnect).
info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1]
Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.ValidationProblemDetails'.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]
Executed action TheNewestDbConnect.Controllers.UserController.Create (TheNewestDbConnect) in 6.680400000000001ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'TheNewestDbConnect.Controllers.UserController.Create (TheNewestDbConnect)'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 11.3971ms 400 application/problem+json; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
I have no idea what is happening and how to solve it. Any help will be strongly appreciated!
Turned out I was just missing an upload handler. Adding this line solved it: webRequest.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(JsonObject));

How to access custom header from AWS Lambda Authorizer?

I have created an Authorizer in AWS API Gateway. This Authorizer refers to a Lambda Function.
I am passing the following values in header, to the API Endpoint using Postman.
{
"type":"TOKEN",
"authorizationToken": "testing2",
"methodArn": "arn:aws:execute-api:us-west-2:444456789012:ymy8tbxw7b/*/GET/"
}
The above header values are received in the Lambda Function. I can see this through the logs in CloudWatch.
I want to pass additional value 'clientID' in the header. So I pass the following values in the header from postman.
{
"type":"TOKEN",
"authorizationToken": "testing2",
"methodArn": "arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/*/GET/",
"clientID" : "1000"
}
In this case, the Lambda function does not get the clientID. I checked various threads in SO, and understood that this can be achieved mapping header. So I did the following.
In the "Method Execution" section of the API method, I created a new header clientID. In the "Integration Request" section, under "HTTP Headers" section I provided the following value
Name: clientID
Mapped from: method.request.header.clientID
After doing the above, I deployed the API and tried to call the method from Postman, but the clientID is shown undefined. Following is the code that I have written in Lambda Function
exports.handler = function(event, context, callback) {
var clientid = event.clientID;
//I always get event.clientID undefined
console.log("The client ID is:" + event.clientID);
}
EDIT
Following is the error from the CloudWatch Log.
START RequestId: 274c6574-dea5-4009-b777-a929f84b9a9d Version: $LATEST
2019-09-19T09:40:25.944Z 274c6574-dea5-4009-b777-a929f84b9a9d INFO The client ID is:undefined
2019-09-19T09:40:25.968Z 274c6574-dea5-4009-b777-a929f84b9a9d ERROR Invoke Error
{
"errorType": "Error",
"errorMessage": "Unauthorized",
"stack": [
"Error: Unauthorized",
" at _homogeneousError (/var/runtime/CallbackContext.js:13:12)",
" at postError (/var/runtime/CallbackContext.js:30:51)",
" at callback (/var/runtime/CallbackContext.js:42:7)",
" at /var/runtime/CallbackContext.js:105:16",
" at Runtime.exports.handler (/var/task/index.js:40:4)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)",
" at process._tickCallback (internal/process/next_tick.js:68:7)"
]
}
I have understood why I was not getting the value in the header. I have done the following
1) Instead of type TOKEN, I used type REQUEST in the header. I understood this by reading the following link. This link also contains code for Request type.
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html
2) I removed all the mapping from Method Request and Integration Request.
3) Deployed the API.

Authenticate from Retrofit with JWT token to Rest server

my server is Flask based, my client is android studio, and i'm communication using retrofit.
The problem is that i'm not able to pass the jwt token correctly from the android to the server after logging in.
With postman it's working good:
{{url}}/auth - I'm logging in as the user, and getting the JWT token.
Later i'm adding "Authorization" header, with the Value "JWT {{jwt_token}}" and
{{url}}/users/john - I'm asking for user info, which is recieved without problems.
The endpoint from android studio:
public interface RunnerUserEndPoints {
// #Headers("Authorization")
#GET("/users/{user}")
Call<RunnerUser> getUser(#Header("Authorization") String authHeader, #Path("user") String user);
The call itself (The access_token is correct before sending!):
final RunnerUserEndPoints apiService = APIClient.getClient().create(RunnerUserEndPoints.class);
Log.i("ACCESS","Going to send get request with access token: " + access_token);
Call<RunnerUser> call = apiService.getUser("JWT" + access_token, username);
Log.i("DEBUG","Got call at loadData");
call.enqueue(new Callback<RunnerUser>() {
#Override
public void onResponse(Call<RunnerUser> call, Response<RunnerUser> response) { ....
The response error log from the server:
File "C:\Users\Yonatan Bitton\RestfulEnv\lib\site-packages\flask_restful\__init__.py", line 595, in dispatch_request
resp = meth(*args, **kwargs)
File "C:\Users\Yonatan Bitton\RestfulEnv\lib\site-packages\flask_jwt\__init__.py", line 176, in decorator
_jwt_required(realm or current_app.config['JWT_DEFAULT_REALM'])
File "C:\Users\Yonatan Bitton\RestfulEnv\lib\site-packages\flask_jwt\__init__.py", line 151, in _jwt_required
token = _jwt.request_callback()
File "C:\Users\Yonatan Bitton\RestfulEnv\lib\site-packages\flask_jwt\__init__.py", line 104, in _default_request_handler
raise JWTError('Invalid JWT header', 'Unsupported authorization type')
flask_jwt.JWTError: Invalid JWT header. Unsupported authorization type
10.0.0.6 - - [30/Sep/2017 01:46:11] "GET /users/john HTTP/1.1" 500 -
My api-client
public class APIClient {
public static final String BASE_URL = "http://10.0.0.2:8000";
private static Retrofit retrofit = null;
public static Retrofit getClient(){
if (retrofit==null){
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
Log.i("DEBUG APIClient","CREATED CLIENT");
return retrofit;
}
}
Actually i'm really stuck. Tried to follow along all of the tutorials at retrofit's website without success.
I'm sure that there is a simple solution, I just need to add "Authorization" Header with Value "JWT " + access_token like it works in postman and that's it! Thanks.
EDIT:
The problem was the build of the access_token in my client.
I did:
JsonElement ans = response.body().get("access_token");
access_token = "JWT " + ans.toString();
Which I should have done:
JsonElement ans = response.body().get("access_token");
access_token = "JWT " + ans.getAsString();
So before it sent "JWT "ey..." " (Double "" )
And now it sends "JWT ey ... "
Let's start to look at what we know about the problem.
We know that the request is sent
We know that the server processes the request
We know that the JWT is invalid thanks to the error:
JWTError('Invalid JWT header', 'Unsupported authorization type')
If we look for that error in the flask_jwt source code, we can see that this is where our error is raised:
def _default_request_handler():
auth_header_value = request.headers.get('Authorization', None)
auth_header_prefix = current_app.config['JWT_AUTH_HEADER_PREFIX']
if not auth_header_value:
return
parts = auth_header_value.split()
if parts[0].lower() != auth_header_prefix.lower():
raise JWTError('Invalid JWT header', 'Unsupported authorization type')
elif len(parts) == 1:
raise JWTError('Invalid JWT header', 'Token missing')
elif len(parts) > 2:
raise JWTError('Invalid JWT header', 'Token contains spaces')
return parts[1]
Basically flask_jwt takes the Authorization header value and tries to split it into two. The function split can split a string by a delimiter, but if you call it without a delimiter it will use whitespace.
That tells us that flask_jwt expects a string that contains 2 parts separated by whitespace, such as space, and that the first part must match the prefix we are using (in this case JWT).
If we go back and look at your client code, we can see that when you are building the value to be put in the Authorization header you are not adding a space between JWT and the actual token:
apiService.getUser("JWT" + access_token, username);
This is what you should have been doing:
apiService.getUser("JWT " + access_token, username);
Notice the space after JWT?

com.box.sdk.BoxAPIException: The API returned an error code: 404

I used function to create metadata with template. but it throw exception
com.box.sdk.BoxAPIException: The API returned an error code: 404
createMetadata(typename, scope, metadata);
I did this and it seems to work.
BoxFile file = new BoxFile(api, "113280761775");
file.createMetadata(new Metadata().add("/test", "test"));
Metadata metadata = file.getMetadata();
System.out.println("printing out meta-data: " + metadata.get("/test"));

couldnot get access token for daemon applications office 365

I have followed the blog http://blogs.msdn.com/b/exchangedev/archive/2015/01/22/building-demon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow.aspx to create a daemon application . I am able to get the app only token for the domain in which i have registered the application . But when I try to get for other organizations it throws an error
"
{"error":"invalid_client","error_description":"AADSTS70002: Error validating cre
dentials. AADSTS50012: Client assertion audience claim does not match Realm issu
er.\r\nTrace ID: 09e025f5-7db9-46c3-9df9-574c6820a011\r\nCorrelation ID: f4d0fa5
7-ee8c-4443-b28b-d372d945f81f\r\nTimestamp: 2015-05-04 13:51:51Z","error_codes":
[70002,50012],"timestamp":"2015-05-04 13:51:51Z","trace_id":"09e025f5-7db9-46c3-
9df9-574c6820a011","correlation_id":"f4d0fa57-ee8c-4443-b28b-d372d945f81f","subm
it_url":null,"context":null}"
But i have configured the application to be multi tenant .
this is the request i make
request https://login.windows.net/<tenantId>/oauth2/to
ken
grant_type=client_credentials
redirect_uri=http://localhost.com:9000
resource=https://outlook.office365.com/
client_assertion_type =urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion="eyJhbGciOiJSUzI1NiIsIng1dCI6IjZlLzEra01scHhuTHArZFJ4d1BqS21EdmZCQT0ifQ.eyJhdWQiOiJodHRwczovL2xvZ2luLndpbmRvd3MubmV0L2ZmNjQxNTFmLTIwM2EtNGM0MC1hZDcxLTExOTE2YjY2Yzg3My9vYXV0aDIvdG9rZW4iLCJleHAiOjE0MzEwMDYzMDMsImlzcyI6ImFkMTkzY2I1LWU2NmUtNDdmNS1iMTc4LTQxM2NlODA3ZDg2YiIsImp0aSI6IjMyMDZiYWI5LTVmYmUtNDA3ZS02OWY2LTJlNGRjNDQ3NzQxYSIsIm5iZiI6MTQzMTAxMTMwMywic3ViIjoiYWQxOTNjYjUtZTY2ZS00N2Y1LWIxNzgtNDEzY2U4MDdkODZiIn0.eEOlhsl-vbdzIiV3AfGFOH187Yb8zpGSGm6RbMhDX4NRJbwOWjJr3eFK3rGXSkl1vhSfJ_oFc69pB1AGfUK8u_SWRl7U3GgH3EJryE-FiVluCQ-ONZ3Qj1u6VggXgTodi0bdvhQF4WlwazXmJGbpeVRUZBm2rlTcd8JtQY96sOu1CRDpZJOFnHzjqleVdrnw8_pNVUafwlnaosRT9tOIgiK9apjN_KY5JMM1QTYKhKk5ZApjmr8agTZpObdz-_Y9znjaSxQcYkFnQeCGc-qwISzH1OqG_7JbCDq6Dp1-oBU5sJneJaF6IxX8-sWyaju3ntMWQyINeuHnRCoPrlp2tg"
this is the assertion i create
token.Header["alg"] = "RS256"
token.Header["x5t"] = "thumbprint of certificate "
token.Claims["aud"] = "https://login.windows.net/" + TenantId + "/oauth2/token"
token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
token.Claims["iss"] = client_id
token.Claims["jti"] = some guid
token.Claims["nbf"] = (time.Now().Add(time.Hour * 72).Unix()) + 5000
token.Claims["sub"] = client_id
please let me what to be done so that i can get the access token for other organiztion's domain .
Thanks in advance