send msg to Azure service bus que via REST - rest

The Azure Queues are exposed to REST API.To make the REST call works. I ran a sample test on POSTMAN. The POST call
https://yournamespace.servicebus.windows.net/yourentity/messages
Also, Passing below 2 headers and values.
Header 1:
Authorization: SharedAccessSignature sr=https%3A%2F%2F.servicebus.windows.net%2Fyourentity&sig=yoursignature from code above&se=1529928563&skn=KeyName
Example:
SharedAccessSignature sr=https%3A%2F%2Fservicebussoatest1.servicebus.windows.net%2Fpublishque&sig=a0wmRklbCGFCYoSCViij9gagtZV9Bg+vU=&se=1529928563&skn=testpolicy
Header 2:
Content-Type: application/json
But even though I have passed the correct Authorization value, I am getting the error below:
401:Invalid Authorization Token signature

401:Invalid Authorization Token signature
According to the 401 error meanings that the token is not vaild.
Firstly please make sure that your policy has access to send the message.
Secondly, if you want to use the azure service bus Send Message Rest APi. The format should be following.
POST https://<yournamespace>.servicebus.windows.net/<yourentity>/messages
Authorization: SharedAccessSignature sr=https%3A%2F%2F<yournamespace>.servicebus.windows.net%2F<yourentity>&sig=<yoursignature from code above>&se=1438205742&skn=KeyName
ContentType: application/atom+xml;type=entry;charset=utf-8
We also could get more information about Service Bus access control with Shared Access
Signatures from this article.
I also do a demo with postman. It works correctly on my side.
I use the following code to get the SAS token.
public static string GetSasToken(string resourceUri, string keyName, string key, TimeSpan ttl)
{
var expiry = GetExpiry(ttl);
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
return sasToken;
}
private static string GetExpiry(TimeSpan ttl)
{
TimeSpan expirySinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1) + ttl;
return Convert.ToString((int)expirySinceEpoch.TotalSeconds);
}
string queueUrl = "https://tomtestsb.servicebus.windows.net/" + "queue" + "/messages";
string token = GetSasToken(queueUrl,"Key", "value", TimeSpan.FromDays(1));
We could get the key and value with Azure portal
Test it with Postman.
Headers:
Authorization:SharedAccessSignature sr=https%3a%2f%2fyournamespace.servicebus.windows.net%2fqueuename%2fmessages&sig=SyumAUNnqWFjW2MqjwlomU%2fbblqZljq6LPJp3jpfU%2b4%3d&se=1529478623&skn=KeyName
Content-Type:application/xml
Body
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">This is a message.</string>
Test Result:

Simple 2 step process:
First you can import the below Curl in postman:
curl --location --request POST '{{topicQueueForAzureServiceBusUri}}' \
--header 'ContentType: application/atom+xml;type=entry;charset=utf-8' \
--header 'Authorization: {{SasTokenForAzureServiceBus}}' \
--header 'Content-Type: application/json' \
--data-raw '{"YOUR JSON"}'
Copy All the key generation script to the prerequisite step of Postman Request and replace first four variable values from your topic/queue config:
var namespace = "YOUR Namespace";
var topicQueueName = "YOUR TOPIC/QUEUE Name";
var sharedAccessKeyName = "YOUR sharedAccessKeyName";
var sharedAccessKey = "YOUR sharedAccessKey";
var topicQueueForAzureServiceBusUri = "https://" + namespace + ".servicebus.windows.net/" + topicQueueName + "/messages";
pm.collectionVariables.set("topicQueueForAzureServiceBusUri", topicQueueForAzureServiceBusUri);
var sasToken = createSharedAccessToken(topicQueueForAzureServiceBusUri, sharedAccessKeyName, sharedAccessKey);
pm.collectionVariables.set("SasTokenForAzureServiceBus", sasToken);
function createSharedAccessToken(uri, saName, saKey) {
if (!uri || !saName || !saKey) {
throw "Missing required parameter";
}
var encoded = encodeURIComponent(uri).toLowerCase();
var now = new Date();
var week = 60*60*24*7;
var ttl = Math.round(now.getTime() / 1000) + week;
var signature = encoded + '\n' + ttl;
var hash = CryptoJS.HmacSHA256(signature, saKey);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
return 'SharedAccessSignature sr=' + encoded + '&sig=' +
encodeURIComponent(hashInBase64) + '&se=' + ttl + '&skn=' + saName;
}

This worked for me:
The url to POST to: https://[ServiceBusNamespace].servicebus.windows.net/[QueueName]/messages
Authorization: use code provided by Tom Sun - MSFT
Content-Type: application/json

Related

Rest Client gives Bad Request for HTTP PUT request

I'm new to Rest Client development. Need your help in figuring out how to get a proper response for below rest service.
curl --location --request PUT 'sandbox-url/TokenGeneratorAPI/v1/update_pay_status' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {{token}' \
--data-raw '{
"pay_id":000000000,
"status":1,
"amount":0.00,
"pay_method":0,
"pay_sys_ref":"test"
}'
I created a class in client side for request object like below.
public class PaymentRqBean {
#XmlElement(name="pay_id")
String pay_id;
#XmlElement(name="status")
String status;
#XmlElement(name="amount")
String amount;
#XmlElement(name="pay_method")
String pay_method;
#XmlElement(name="pay_sys_ref")
String pay_sys_ref;
public String getPay_id() {
return pay_id;
}
public void setPay_id(String pay_id) {
this.pay_id = pay_id;
}
}
......and getters setters for other attributes
And created a method for calling the web service in another class like below.
public PaymentRsBean callWS(PaymentRqBean pReq) {
PaymentRsBean prs = new PaymentRsBean();
Client client = ClientBuilder.newClient();
client.register(new Authenticator(com.boc.conf.Configurations.objProperty.getProperty("ikUserName"), com.boc.conf.Configurations.objProperty.getProperty("ikPassword")));
WebTarget webTarget = client.target(url);
Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);
Response response = invocationBuilder.accept(MediaType.APPLICATION_JSON).put(Entity.json(pReq));
I'm getting HTTP 400 BAD REQUEST for above. I would be so thankful for any help given in solving this.
(Is it because #XmlRootElement? )
The problem is the way you are defining the attributes of your PaymentRqBean class.
The variables 'pay_id', 'status', 'amount' and 'pay_method' must be of numeric type (int, double...), since the request you launch indicates that they are numeric, not Strings.
"pay_id":000000000,
"status":1,
"amount":0.00,
"pay_method":0

Missing request header 'authToken' calling RestAPI method

I have this RestAPI method
#GetMapping(path = "/menus",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<List<MenuPriceSummary>> allMenus(HttpServletRequest request, #RequestHeader(value="Authorization: Bearer") String authToken) {
String username = jwtTokenUtil.getUsernameFromToken(authToken);
User user = userService.findByUserName(username);
return ResponseEntity.ok(menuService.allMenus(user));
}
which I call from curl
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJsb3Blei5hbnRvbmlvODVAZ21haWwuY29tIiwiZXhwIjoxNTk0MTkzNDYwLCJpYXQiOjE1MzM3MsM0NjB9.9pXvdiRMM5fjE4Ur5nqKvwvRLmNWyn6tY6y5fPXOg_BWEW2sJ8vnrLTXPfiA-Sc6Qk2XTwi6FhlIhFEQKip4aQ" "http://127.0.0.1:1133/canPeris/api/v1/users/menus"
But I got this error:
"status":400,"error":"Bad Request","message":"Missing request header 'Authorization: Bearer' for method parameter of type String"'authToken' for method parameter of type String","tr....
You can't use #RequestHeader that way. The values from the headers get split up by : and added to a Map, so every value containing a : is impossible.
You will have to change your annotation to #RequestHeader(value="Authorization") and then remove the Bearer from the authToken.
Spring MVC provides annotation #RequestHeader that can be used to map controller parameter to request header value .
Can you please change your method to
#GetMapping(path = "/menus",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<List<MenuPriceSummary>> allMenus(
#RequestHeader(value="Authorization") String authToken,
HttpServletRequest request) {
String username = jwtTokenUtil.getUsernameFromToken(authToken);
User user = userService.findByUserName(username);
return ResponseEntity.ok(menuService.allMenus(user));
}
You can also make use of Interceptors to validate headers so that other rest endpoints in your application can make use of it .

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?

Is it possible to use the OpenStack.NET SDK with SoftLayer object storage?

SoftLayer Object Storage is based on the OpenStack Swift object store.
SoftLayer provide SDKs for their object storage in Python, Ruby, Java and PHP, but not in .NET. Searching for .NET SDKs for OpenStack, I came across OpenStack.NET.
Based on this question OpenStack.NET is designed for use with Rackspace by default, but can be made to work with other OpenStack providers using CloudIdentityWithProject and OpenStackIdentityProvider.
SoftLayer provide the following information for connecting to their Object Storage:
Authentication Endpoint
Public: https://mel01.objectstorage.softlayer.net/auth/v1.0/
Private: https://mel01.objectstorage.service.networklayer.com/auth/v1.0/
Username:
SLOS123456-1:email#example.com
API Key (Password):
1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
It's not obvious how this would map to the fields of CloudIdentityWithProject, and OpenStackIdentityProvider but I tried the following and a few other combinations of project name / username / uri:
var cloudIdentity = new CloudIdentityWithProject()
{
ProjectName = "SLOS123456-1",
Username = "email#example.com",
Password = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
};
var identityProvider = new OpenStackIdentityProvider(
new Uri("https://mel01.objectstorage.softlayer.net/auth/v1.0/"),
cloudIdentity);
var token = identityProvider.GetToken(null);
However, in all cases I received the following error:
Unable to authenticate user and retrieve authorized service endpoints
Based on reviewing the source code for SoftLayer's other language libraries and for OpenStack.NET, it looks like SoftLayer's object storage uses V1 auth, while OpenStack.NET is using V2 auth.
Based on this article from SoftLayer and this article from SwiftStack, V1 auth uses a /auth/v1.0/ path (like the one provided by SoftLayer), with X-Auth-User and X-Auth-Key headers as arguments, and with the response contained in headers like the following:
X-Auth-Token-Expires = 83436
X-Auth-Token = AUTH_tk1234567890abcdef1234567890abcdef
X-Storage-Token = AUTH_tk1234567890abcdef1234567890abcdef
X-Storage-Url = https://mel01.objectstorage.softlayer.net/v1/AUTH_12345678-1234-1234-1234-1234567890ab
X-Trans-Id = txbc1234567890abcdef123-1234567890
Connection = keep-alive
Content-Length = 1300
Content-Type = text/html; charset=UTF-8
Date = Wed, 14 Oct 2015 01:19:45 GMT
Whereas V2 auth (identity API V2.0) uses a /v2.0/tokens path, with the request and response in JSON objects in the message body.
Based on the OpenStackIdentityProvider class in OpenStack.NET I hacked together my own SoftLayerOpenStackIdentityProvider like this:
using JSIStudios.SimpleRESTServices.Client;
using net.openstack.Core.Domain;
using net.openstack.Providers.Rackspace;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenStack.Authentication;
using System;
using System.Linq;
using System.Collections.Generic;
namespace OpenStackTest1
{
public class SoftLayerOpenStackIdentityProvider : CloudIdentityProvider
{
public SoftLayerOpenStackIdentityProvider(
Uri urlBase, CloudIdentity defaultIdentity)
: base(defaultIdentity, null, null, urlBase)
{
if (urlBase == null)
throw new ArgumentNullException("urlBase");
}
public override UserAccess GetUserAccess(
CloudIdentity identity, bool forceCacheRefresh = false)
{
identity = identity ?? DefaultIdentity;
Func<UserAccess> refreshCallback =
() =>
{
// Set up request headers.
Dictionary<string, string> headers =
new Dictionary<string, string>();
headers["X-Auth-User"] = identity.Username;
headers["X-Auth-Key"] = identity.APIKey;
// Make the request.
JObject requestBody = null;
var response = ExecuteRESTRequest<JObject>(
identity,
UrlBase,
HttpMethod.GET,
requestBody,
headers: headers,
isTokenRequest: true);
if (response == null || response.Data == null)
return null;
// Get response headers.
string authToken = response.Headers.Single(
h => h.Key == "X-Auth-Token").Value;
string storageUrl = response.Headers.Single(
h => h.Key == "X-Storage-Url").Value;
string tokenExpires = response.Headers.Single(
h => h.Key == "X-Auth-Token-Expires").Value;
// Convert expiry from seconds to a date.
int tokenExpiresSeconds = Int32.Parse(tokenExpires);
DateTimeOffset tokenExpiresDate =
DateTimeOffset.UtcNow.AddSeconds(tokenExpiresSeconds);
// Create UserAccess via JSON deseralization.
UserAccess access = JsonConvert.DeserializeObject<UserAccess>(
String.Format(
"{{ " +
" token: {{ id: '{0}', expires: '{1}' }}, " +
" serviceCatalog: " +
" [ " +
" {{ " +
" endpoints: [ {{ publicUrl: '{2}' }} ], " +
" type: 'object-store', " +
" name: 'swift' " +
" }} " +
" ], " +
" user: {{ }} " +
"}}",
authToken,
tokenExpiresDate,
storageUrl));
if (access == null || access.Token == null)
return null;
return access;
};
string key = string.Format("{0}:{1}", UrlBase, identity.Username);
var userAccess = TokenCache.Get(key, refreshCallback, forceCacheRefresh);
return userAccess;
}
protected override string LookupServiceTypeKey(IServiceType serviceType)
{
return serviceType.Type;
}
}
}
Because some of the members of UserAccess (like IdentityToken and Endpoint) have no way to set their fields (the objects have only a default constructor and only read-only members), I had to create the UserAccess object by deserializing some temporary JSON in a similar format as returned by the V2 API.
This works, ie I can now connect like this:
var cloudIdentity = new CloudIdentity()
{
Username = "SLOS123456-1:email#example.com",
APIKey = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
};
var identityProvider = new SoftLayerOpenStackIdentityProvider(
new Uri("https://mel01.objectstorage.softlayer.net/auth/v1.0/"),
cloudIdentity);
var token = identityProvider.GetToken(null);
And then get access to files etc like this:
var cloudFilesProvider = new CloudFilesProvider(identityProvider);
var containers = cloudFilesProvider.ListContainers();
var stream = new MemoryStream();
cloudFilesProvider.GetObject("testcontainer", "testfile.dat", stream);
However, is there a better way than this to use SoftLayer Object Storage from .NET?
I briefly also looked at the OpenStack SDK for .NET (a different library to OpenStack.NET), but it too seems to be based on V2 auth.

How to get a paypal access token using REST request

I'm trying to get this working https://developer.paypal.com/webapps/developer/docs/integration/direct/make-your-first-call/
Using Java + Jersey application. It seems like I'm missing something in POST params.
public String getPaypalToken() {
Client client = Client.create();
WebResource webResource = client.resource("https://api.sandbox.paypal.com/v1/oauth2/token");
MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
queryParams.add("username", CLIENT_ID + ":" + SECRET );
queryParams.add("grant_type", "client_credentials");
ClientResponse response = webResource.accept("application/json").acceptLanguage("en_US").type("application/x-www-form-urlencoded").post(ClientResponse.class, queryParams);
return response.toString();
}
Using previous code I got: POST https://api.sandbox.paypal.com/v1/oauth2/token returned a response status of 401 Unauthorized.
This CURL command line option just works fine:
curl -X POST https://api.sandbox.paypal.com/v1/oauth2/token -H "Accept: application/json" -H "Accept-Language: en_US" -u "EOJ2S-Z6OoN_le_KS1d75wsZ6y0SFdVsY9183IvxFyZp:EClusMEUk8e9ihI7ZdVLF5cZ6y0SFdVsY9183IvxFyZp" -d "grant_type=client_credentials"
Any suggestions will be appreciated.
J.
The -u option in curl sends a base64 encoded "username:password" string. I don't think adding client id / secret to the queryParams map does the same (unless Jersey treats the 'username' key differently which I don't think it does).
You should instead try
webResource.header("Authorization", "Basic " + Base64.encode(CLIENT_ID + ":" + SECRET.getBytes()))
Just sharing my solution:
Dictionary<string, string> sdkConfig = new Dictionary<string, string>();
sdkConfig.Add("mode", "sandbox");
string clientid = "<your client id>";
string secretid = "<your secret id>";
string accessToken = new OAuthTokenCredential(clientid, secretid, sdkConfig).GetAccessToken();
I previously encountered unauthorized response using RestSharp, then found this. I'm using paypal .net sdk from nuget package.
Reference.