I have an Azure Hybrid Connection that's supposed to connect to some on-prem service and expose it to my app services. However, the setup is failing somewhere, and I'm trying to narrow down exactly what the problem is.
As part of this process (and because it would be useful to me in the future) I'm trying to make a call to the underlying on-prem service using SoapUI, but the initial GET request that's supposed to give me the WSDL is instead giving me an authentication error:
GET https://my-relay.servicebus.windows.net/my-endpoint/my-service.svc?wsdl
{
"error": {
"code": "TokenMissingOrInvalid",
"message": "MissingToken: Relay security token is required. TrackingId:b58c004c-e0e6-4dd0-a233-e0d304795e4e_G21, SystemTracker:my-relay.servicebus.windows.net:my-endpoint/my-service.svc, Timestamp:2019-03-05T10:17:26"
}
}
From where do I get the Relay security token, and how do I tell SoapUI about it?
This guide may give you the answers you need.
https://www.soapui.org/soap-and-wsdl/authenticating-soap-requests.html
I suspect your normal app automatically accesses the webservice as the current user on the current system. If so, I believe you should look at the NTLM authentication.
You need to create a security token and pass it in the header of your request.
Something like this:
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key);
var uri = new Uri(string.Format("https://{0}/{1}", RelayNamespace, ConnectionName));
var token = (await tokenProvider.GetTokenAsync(uri.AbsoluteUri, TimeSpan.FromHours(1))).TokenString;
var client = new HttpClient();
var request = new HttpRequestMessage()
{
RequestUri = uri,
Method = HttpMethod.Get,
};
request.Headers.Add("ServiceBusAuthorization", token);
var response = await client.SendAsync(request);
For SOAPUI, you would add the resultant token value in a header named "ServiceBusAuthorization."
Related
We are experiencing an issue calling an On-premise API endpoint from our Azure Function and I'm at a loss to the reason.
We are getting the following error: "x509 certificate signed by unknown authority" back as a 500 status code, which is strange considering we are using the appropriate code within the HttpClientHandler code.
Specifically, we have code that calls an OAuth endpoint which we get a response for, so definitely goes through our firewall and returns a 200 OK response. This endpoint has a DigiCert certificate.
In the same function, this then calls the functional endpoint to return some user data. This comes back with a 500 Internal Server error. This endpoint has a PKI certificate.
There is some level of NSG/Azure Firewall and On Premise setup involved but wondering whether anyone has experienced this before as I'm stumped on next steps.
Sample code looks this as follows
using (HttpClientHandler httpClientHandler = new HttpClientHandler() {
CheckCertificateRevocationList = false,
ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
}) {
using (HttpClient client = new HttpClient(httpClientHandler))
{
return await GetEligibilityToken(client);
}
}
// OAuth Endpoint - This works as expected
var token = Task.Run(() => TokenRetriever.GetEligibilityToken()).GetAwaiter().GetResult();
// Call the User Endpoint - This does not work, configured by
// ConfigurePrimaryHttpMessageHandler with same
// ServerCertificateCustomValidationCallback options.
string apiEndpoint = Constants.SSOApiEndpointDomain;
string path = $#"{apiEndpoint}/v1.0/users/813229bc-3a32-4457-85d5-af7b70db85e0";
// Add the token
_httpClient.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", token.AccessToken);
var response = await _httpClient.GetAsync(path).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
string data = response.Content.ReadAsStringAsync().Result; code here
Note - I'm aware of the suboptimal use of using HttpClient, I've tried both that and ConfigurePrimaryHttpMessageHandler options.
Any help or advice you could give would be greatly appreciated. I'm even starting to wonder whether we can call services with PKI certs via Azure Functions.
J
Edit - I should say the code works fine "locally" (albeit I appreciate it needs cleaning up) and we get the desired behaviour. I do have the appropriate CA authority certs on my own VM.
var authContext = new AuthenticationContext(Constants.AUTHORITY);
var credential =
new ClientCredential(Constants.CLIENT_ID, Constants.CLIENT_SECRET);
var result = (AuthenticationResult)authContext
.AcquireTokenAsync(Constants.API_ID_URL, credential)
.Result;
var token = result.AccessToken;
return token;
Using the above code to get bearer token, I am getting wrong / incomplete bearer token. Then adding into client header.
client.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage res = client.GetAsync(urlParameters).Result;
response is unauthorized.
The token is correct. Your code looks fine too. Two possible reasons that come to mind:
Double check that the identity you are using actually has access to the service you are trying to access.
Make sure you are calling the api correctly. Services/endpoints have different requirements. You might get something like that if your call is incorrect, let's say you didn't provide an API version when it is required.
It would help if you provided full response body you are getting, and the full request you are making. You can obfuscate personal data.
I configured azure application proxy for our on-premise hosted web service and turned on Azure AD authentication. I am able to authenticate using ADAL but must find a way to get the token and call web service without ADAL now (we are going to use this from Dynamics 365 online and in sandbox mode I can't use ADAL). I followed some examples regarding service to service scenario and I successfully retrieve the token using client credentials grant flow. But when I try to call the app proxy with Authorization header and access token, I receive an error "This corporate app can't be accessed right now. Please try again later". Status code is 500 Internal server error.
Please note the following:
I don't see any error in app proxy connectors event log.
I added tracing on our on-premise server and it seems like the call never comes there.
If I generate token with ADAL for a NATIVE app (can't have client_secret so I can't use client credentials grant flow), I can call the service.
I created an appRole in manifest for service being called and added application permission to the client app.
This is the way I get the token:
public async static System.Threading.Tasks.Task<AzureAccessToken> CreateOAuthAuthorizationToken(string clientId, string clientSecret, string resourceId, string tenantId)
{
AzureAccessToken token = null;
string oauthUrl = string.Format("https://login.microsoftonline.com/{0}/oauth2/token", tenantId);
string reqBody = string.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&resource={2}", Uri.EscapeDataString(clientId), Uri.EscapeDataString(clientSecret), Uri.EscapeDataString(resourceId));
HttpClient client = new HttpClient();
HttpContent content = new StringContent(reqBody);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
using (HttpResponseMessage response = await client.PostAsync(oauthUrl, content))
{
if (response.IsSuccessStatusCode)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(AzureAccessToken));
Stream json = await response.Content.ReadAsStreamAsync();
token = (AzureAccessToken)serializer.ReadObject(json);
}
}
return token;
}
AzureAccessToken is my simple class marked for serialization.
I assume it must be something I haven't configured properly. Am I missing some permissions that are required for this scenario?
Any help is appriciated.
I have a continuously scheduled web job that's monitoring a message queue, pulling messages off and calling a Web API on the peer Web Site to process the messages (in this case using SignalR to send notifications to appropriate users).
What would be the best way in this case to call the web API securely? The API being hosted in the web site is obviously exposed otherwise. Perhaps something using Basic Auth or storing a security token in config and passing it from the job to the web API. Or creating a custom AuthorizeAttribute?
Ant thoughts on securing the Web API call from the WebJob would be much appreciated. The API should only be callable from the WebJob.
UPDATE:
Something like this perhaps?
First I declare this class;
public class TokenAuthenticationHeaderValue : AuthenticationHeaderValue
{
public TokenAuthenticationHeaderValue(string token)
: base("Token", Convert.ToBase64String(Encoding.UTF8.GetBytes(token)))
{ }
}
Then the caller (the WebJob) uses this class to set an auth header when making the HTTP request;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(/* something */);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new TokenAuthenticationHeaderValue("TOKEN FROM CONFIG");
// ....
Over in the Web API we check the request looking for the expected token in the auth header, currently the code is pretty ugly but this could be put into a custom attribute;
public HttpResponseMessage Post([FromBody]TheThing message)
{
var authenticationHeader = Request.Headers.Authorization;
var token = Encoding.UTF8.GetString(Convert.FromBase64String(authenticationHeader.Parameter));
if (authenticationHeader.Scheme != "Token" || token != "TOKEN FROM CONFIG")
{
return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "No, no, no. That's naughty!");
}
// All OK, carry on.
So this way the WebJob calls the Web API on the peer web site and security is achieved by passing a token that is securely held in the Azure configuration, both the Site and Job have access to this token.
Any better ideas?
Sounds like Basic Authentication would be fine for your scenario.
Great tutorial here: Basic Authentication
Lets say I have a web client (i.e. MVC 4 client) that authenticates users using an oAuth provider (i.e. Facebook, Google etc).
I want to call another web service in my client logic, and that web service also authenticates with oAuth providers.
What would the web service request look like from the client? What do I need to pass to the web service?
I suggest you review this question, How do I authorize access to ServiceStack resources using OAuth2 access tokens via DotNetOpenAuth?. The poster provided his final solution, including a link to a sample solution, which he has graciously open sourced. The client side code, for his solution, looks like this:
// Create the ServiceStack API client and the request DTO
var apiClient = new JsonServiceClient("http://api.mysite.com/");
var apiRequestDto = new Shortlists { Name = "dylan" };
// Wire up the ServiceStack client filter so that DotNetOpenAuth can
// add the authorization header before the request is sent
// to the API server
apiClient.LocalHttpWebRequestFilter = request => {
// This is the magic line that makes all the client-side magic work :)
ClientBase.AuthorizeRequest(request, accessTokenTextBox.Text);
}
// Send the API request and dump the response to our output TextBox
var helloResponseDto = apiClient.Get(apiRequestDto);
Console.WriteLine(helloResponseDto.Result);
A similar solution is provided here: https://stackoverflow.com/a/13791078/149060 which demonstrates request signing as per OAuth 1.0a
var client = new JsonServiceClient (baseUri);
client.LocalHttpWebRequestFilter += (request) => {
// compute signature using request and a previously obtained
// access token
string authorization_header = CalculateSignature (request, access_token);
request.Headers.Add ("Authorization", authorization_header);
};
var response = client.Get<MySecuredResponse> ("/my/service");
You will, of course, need to adjust to fit the requirements of your OAuth providers, i.e. signing, token, etc.