I am developing a game using Monogame and I want to access my Api so that I can make a login but it always returns me an exception. If I use port 80 I get the following one No connection could be made because the target machine actively refused it and if I use port 5000 I get a 401: Not authorized .
By printing in the console I could come to the conclusion that my try is interrupted at the line response = await client.GetStringAsync(builder.Uri.AbsoluteUri);
Is there something wrong with my code?
Communication class
public class Communication
{
private readonly HttpClient client = new HttpClient();
private const string Uri = "http://localhost:5000/";
private const int Port = 5000;
public Communication()
{
}
public async Task<User> Login(string username, string password)
{
string response;
User user = null;
try
{
var builder = new UriBuilder(Uri + "/Api/Account/Login/")
{
Port = Port
};
builder.Query = $"Username={username}&Password={password}";
Debug.WriteLine("Chegou Aqui!!!!")
response = await client.GetStringAsync(builder.Uri.AbsoluteUri);
if (response == "OK")
{
user = JsonConvert.DeserializeObject<User>(response);
}
}
catch (Exception ex)
{
Debug.WriteLine("\tERROR {0}", ex.Message);
}
return user;
}
}
My Api Login Method
[AllowAnonymous]
[HttpPost("Login")]
public IActionResult Authenticate([FromBody]AuthenticateModel userModel)
{
var user = _userService.Authenticate(userModel.Username, userModel.Password);
if(user == null)
{
return BadRequest(new { message = "Username or Password invalid" });
}
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return Ok(new
{
Id = user.Id,
UserName = user.Username,
Token = tokenString
}) ;
}
This article possibly can help you
You can check your firewall settings or if any antivirus installed in your system, make sure to check the settings of it.
You get error 401: Not authorized because HTTP requests by default configured on port 80, not any other ports.
If the problem persists, check your router or switch configuration, if any is in your route to server.
Related
I have an issue that I'm now completely at a loss over.
I have an authentication server that creates and sends JWT's to a unity application (android/VR).
The auth server creates a token as such
private string GenerateJwtToken(User user)
{
var symmetricKey = Convert.FromBase64String(_tokenSettings.Secret);
var expires = DateTime.Now.AddMinutes(Convert.ToInt32(15));
var tokenHandler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.PrimarySid, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.GivenName, user.FirstName),
new Claim(ClaimTypes.Surname, user.LastName),
new Claim("company", user.Company),
new Claim(ClaimTypes.Role, "api_user"),
new Claim(ClaimTypes.Expiration, $"{expires.ToShortDateString() + " " + expires.ToShortTimeString()}"),
}),
Expires = expires,
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(symmetricKey),
SecurityAlgorithms.HmacSha256Signature)
};
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(securityToken);
return token;
}
I have no issues decoding this and getting out the claims in a console application. This is where the confusion comes in. When I try and perform the same task in Unity and build the application to the VR headset, I'm met with issues, namely this
"IDX10729: Unable to decode the header 'header' as Base64Url encoded string. jwtEncodedString: 'Token here'."
The unity auth service looks like this
public async Task<string> GetAccessToken(string username, string password)
{
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage())
{
//TODO: Replace this hardcoded URL value here.
request.RequestUri = new Uri("{{URL Emmited}}");
request.Method = HttpMethod.Post;
var body = new AuthRequest()
{
Username = username,
Password = password
};
var content = new StringContent(JsonConvert.SerializeObject(body), encoding: Encoding.UTF8, "application/json");
request.Content = content;
var response = await client.SendAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
var tokenContent = JsonConvert.DeserializeObject<Response>(responseContent);
var token = tokenContent.Token;
return token;
}
}
}
and retrieving the claims, I've tried two different ways
public string GetUserName(string token)
{
try
{
var securityToken = new JwtSecurityToken(token);
return securityToken?.Claims.First(claim => claim.Type == "given_name").Value;
}
catch (Exception exception)
{
//log exception here
return string.Empty;
}
}
and
public string GetUserName(string token)
{
try
{
var handler = new JwtSecurityTokenHandler();
var securityToken = handler.ReadJwtToken(token);
return securityToken?.Claims.First(claim => claim.Type == "given_name").Value;
}
catch (Exception exception)
{
//log exception here
return string.Empty;
}
}
ReadJwtToken internally just creates a new JwtSecurityToken object so I assume there's something in that I'm missing.
Both of these throw the same "Unable to decode the header 'header' as Base64Url encoded string" error, however, if I do handler.CanReadToken(token); this returns true, which baffles me even more.
Anyone have any ideas as to why this is happening and any clues on how to fix it.
some further information; the token I retrieve can be decoded in JWT.io and in a console app, I'm using the dotnet standard 2.0 assemblies for System.IdentityModel, System.IdentityModel.Tokens.JWT, System.IdentityModel.Tokens, System.IdentityModel.Logging and Newtonsoft.Json
I have my below code which output the master branch stats in JSON format from Azure DevOps repository and I am capturing the required output. This works when I use the personal access token the authentication works and gets back with the results from the API.
But when I try to generate Access token using the registered app in AAD(has delegated user impersonation enabled for Azure DevOps under API permissions), I am able to generate the access token and then passing it while calling the API, but it returns back with
StatusCode: 203, ReasonPhrase: 'Non-Authoritative Information', Version: 1.1, Content: System.Net.Http.StreamContent
public static async Task GetBuilds()
{
string url = "Azure Dev-Ops API";
var personalaccesstoken = "personalaccesscode";
//var personalaccesstoken = token.GetYourTokenWithClientCredentialsFlow().Result;
string value = null;
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalaccesstoken))));
using (HttpResponseMessage response = await client.GetAsync(url))
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
dynamic jsonObject = JsonConvert.DeserializeObject(responseBody);
value = jsonObject;
}
}
if (value != null)
{
Console.WriteLine(value);
}
}
public static async Task<string> GetYourTokenWithClientCredentialsFlow()
{
string tokenUrl = $"https://login.microsoftonline.com/{tenant ID}/oauth2/token";
var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenUrl);
tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = "client ID",
["client_secret"] = "client secret",
["resource"] = "https://graph.microsoft.com/"
});
dynamic json;
dynamic token;
string accessToken;
HttpClient client = new HttpClient();
var tokenResponse = client.SendAsync(tokenRequest).Result;
json = await tokenResponse.Content.ReadAsStringAsync();
token = JsonConvert.DeserializeObject(json);
accessToken = token.access_token;
return accessToken;
}
Tried to test using postman using the access token generated using above code and get as below screenshot.
what I am doing wrong here and how can I fix the problem?
The azure ad access token is a bearer token. You do not need to use it as basic auth.
Try with the following code:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", GetYourTokenWithClientCredentialsFlow().Result);
Update:
Register a new app
Set the app as a public client by default
Add permission to DevOps API
Create a new project, install Microsoft.IdentityModel.Clients.ActiveDirectory package
Code sample
class Program
{
static string azureDevOpsOrganizationUrl = "https://dev.azure.com/jack0503/"; //change to the URL of your Azure DevOps account; NOTE: This must use HTTPS
static string clientId = "0a1f****-****-****-****-a2a4****7f69"; //change to your app registration's Application ID
static string replyUri = "https://localhost/"; //change to your app registration's reply URI
static string azureDevOpsResourceId = "499b84ac-1321-427f-aa17-267ca6975798"; //Constant value to target Azure DevOps. Do not change
static string tenant = "hanxia.onmicrosoft.com"; //your tenant ID or Name
static String GetTokenInteractively()
{
AuthenticationContext ctx = new AuthenticationContext("https://login.microsoftonline.com/" + tenant); ;
IPlatformParameters promptBehavior = new PlatformParameters(PromptBehavior.Auto | PromptBehavior.SelectAccount);
AuthenticationResult result = ctx.AcquireTokenAsync(azureDevOpsResourceId, clientId, new Uri(replyUri), promptBehavior).Result;
return result.AccessToken;
}
static String GetToken()
{
AuthenticationContext ctx = new AuthenticationContext("https://login.microsoftonline.com/" + tenant); ;
UserPasswordCredential upc = new UserPasswordCredential("jack#hanxia.onmicrosoft.com", "yourpassword");
AuthenticationResult result = ctx.AcquireTokenAsync(azureDevOpsResourceId, clientId, upc).Result;
return result.AccessToken;
}
static void Main(string[] args)
{
//string token = GetTokenInteractively();
string token = GetToken();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(azureDevOpsOrganizationUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = client.GetAsync("_apis/projects").Result;
if (response.IsSuccessStatusCode)
{
Console.WriteLine("\tSuccesful REST call");
var result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
}
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
throw new UnauthorizedAccessException();
}
else
{
Console.WriteLine("{0}:{1}", response.StatusCode, response.ReasonPhrase);
}
Console.ReadLine();
}
}
}
For an integration test I have an authorized .NET Core 2.2 Controller that is calling another authorized controller (different project) or external api (like Microsoft Graph).
Both apis are authenticated against the Azure AD. In all the controller actions we need the authenticated user.
We can get in the first api by getting a token based on the username and password (grant_type=password). When the call continues to the second api, it breaks because of an interactive login prompt (We use ADAL).
Normally, the user authenticates with open id connect, we then have the authentication code and get the accesstoken + refresh token with the authentication code. With the refresh token we can get an access token for the second api.
We created a small sample project with default Values Controllers to explain our problem.
Get access token before calling the first api with native app registration:
public static async Task<string> AcquireTokenAsync(string username, string password)
{
var aadInstance = "https://login.windows.net/{0}";
var tenantId = "put id here";
var authority = string.Format(aadInstance, tenantId);
var clientId = "clientid here";
var resource = "put resource here";
var client = new HttpClient();
var tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
var body = $"resource={resource}&client_id={clientId}&grant_type=password&username={username}&password={password}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
var result = await client.PostAsync(tokenEndpoint, stringContent).ContinueWith((response) =>
{
return response.Result.Content.ReadAsStringAsync().Result;
});
JObject jobject = JObject.Parse(result);
var token = jobject["access_token"].Value<string>();
return token;
}
First API:
[Authorize]
[HttpGet]
public async Task<IActionResult> Get()
{
string name = User.Identity.Name;
var result = await AcquireTokenSilentWithImpersonationAsync();
string BaseUrl = "https://localhost:44356/";
var client = new HttpClient
{
BaseAddress = new Uri(BaseUrl)
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
var url = "api/values";
HttpResponseMessage response = await client.GetAsync(url);
switch (response.StatusCode)
{
case HttpStatusCode.OK:
int x = 1;
break;
default:
throw new HttpRequestException($"Error - {response.StatusCode} in response with message '{response.RequestMessage}'");
}
return Ok();
}
private const string BackendResource = "Second api resource here";
/// <summary>
/// For more information: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-devhowto-adal-error-handling
/// </summary>
/// <returns></returns>
public async Task<AuthenticationResult> AcquireTokenSilentWithImpersonationAsync()
{
const string ClientId = "client id of first api here";
const string ClientSecret = "secret of first api here";
ClientCredential credential = new ClientCredential(ClientId, ClientSecret);
string userObjectId = _httpContextAccessor.HttpContext.User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value;
var authContext = GetAuthenticationContext(userObjectId);
AuthenticationResult authResult = null;
try
{
authResult = await authContext.AcquireTokenSilentAsync(BackendResource, credential, new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));
}
catch (AdalSilentTokenAcquisitionException ex)
{
// Exception: AdalSilentTokenAcquisitionException
// Caused when there are no tokens in the cache or a required refresh failed.
// Action: Case 1, resolvable with an interactive request.
try
{
authResult = await authContext.AcquireTokenAsync(BackendResource, ClientId, new Uri("https://backurl.org"), new PlatformParameters(), new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));
}
catch (Exception exs)
{
throw;
}
}
catch (AdalException e)
{
// Exception: AdalException
// Represents a library exception generated by ADAL .NET.
// e.ErrorCode contains the error code.
// Action: Case 2, not resolvable with an interactive request.
// Attempt retry after a timed interval or user action.
// Example Error: network_not_available, default case.
throw;
}
return authResult;
}
Second api:
[Authorize]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
string name = User.Identity.Name;
return new string[] { "value1", "value2" };
}
You need to use the On-behalf-of flow in your Web API (not the interactive token acquisition, need)
If you want to use ADAL.NET, a sample is there: https://github.com/azure-samples/active-directory-dotnet-webapi-onbehalfof
but I would now recommend you use MSAL.NET. the sample is: active-directory-dotnet-native-aspnetcore-v2/2. Web API now calls Microsoft Graph, and the documentation: https://aka.ms/msal-net-on-behalf-of
Also note that for Web APIs, we don't use OIDC (this is to sign-in users), but rather a JWT bearer middleware
I'm trying to implement Identity Server 4 with AspNet Core using Authorization Code Flow.
The thing is, the IdentityServer4 repository on github have several samples, but none with Authorization Code Flow.
Does anyone have a sample on how to implement Authorization Code Flow with Identity Server 4 and a Client in MVC consuming it?
Here's an implementation of an Authorization Code Flow with Identity Server 4 and an MVC client to consume it.
IdentityServer4 can use a client.cs file to register our MVC client, it's ClientId, ClientSecret, allowed grant types (Authorization Code in this case), and the RedirectUri of our client:
public class Clients
{
public static IEnumerable<Client> Get()
{
var secret = new Secret { Value = "mysecret".Sha512() };
return new List<Client> {
new Client {
ClientId = "authorizationCodeClient2",
ClientName = "Authorization Code Client",
ClientSecrets = new List<Secret> { secret },
Enabled = true,
AllowedGrantTypes = new List<string> { "authorization_code" }, //DELTA //IdentityServer3 wanted Flow = Flows.AuthorizationCode,
RequireConsent = true,
AllowRememberConsent = false,
RedirectUris =
new List<string> {
"http://localhost:5436/account/oAuth2"
},
PostLogoutRedirectUris =
new List<string> {"http://localhost:5436"},
AllowedScopes = new List<string> {
"api"
},
AccessTokenType = AccessTokenType.Jwt
}
};
}
}
This class is referenced in the ConfigurationServices method of the Startup.cs in the IdentityServer4 project:
public void ConfigureServices(IServiceCollection services)
{
////Grab key for signing JWT signature
////In prod, we'd get this from the certificate store or similar
var certPath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "SscSign.pfx");
var cert = new X509Certificate2(certPath);
// configure identity server with in-memory stores, keys, clients and scopes
services.AddDeveloperIdentityServer(options =>
{
options.IssuerUri = "SomeSecureCompany";
})
.AddInMemoryScopes(Scopes.Get())
.AddInMemoryClients(Clients.Get())
.AddInMemoryUsers(Users.Get())
.SetSigningCredential(cert);
services.AddMvc();
}
For reference, here are the Users and Scopes classes referenced above:
public static class Users
{
public static List<InMemoryUser> Get()
{
return new List<InMemoryUser> {
new InMemoryUser {
Subject = "1",
Username = "user",
Password = "pass123",
Claims = new List<Claim> {
new Claim(ClaimTypes.GivenName, "GivenName"),
new Claim(ClaimTypes.Surname, "surname"), //DELTA //.FamilyName in IdentityServer3
new Claim(ClaimTypes.Email, "user#somesecurecompany.com"),
new Claim(ClaimTypes.Role, "Badmin")
}
}
};
}
}
public class Scopes
{
// scopes define the resources in your system
public static IEnumerable<Scope> Get()
{
return new List<Scope> {
new Scope
{
Name = "api",
DisplayName = "api scope",
Type = ScopeType.Resource,
Emphasize = false,
}
};
}
}
The MVC application requires two controller methods. The first method kicks-off the Service Provider (SP-Initiated) workflow. It creates a State value, saves it in cookie-based authentication middleware, and then redirects the browser to the IdentityProvider (IdP) - our IdentityServer4 project in this case.
public ActionResult SignIn()
{
var state = Guid.NewGuid().ToString("N");
//Store state using cookie-based authentication middleware
this.SaveState(state);
//Redirect to IdP to get an Authorization Code
var url = idPServerAuthUri +
"?client_id=" + clientId +
"&response_type=" + response_type +
"&redirect_uri=" + redirectUri +
"&scope=" + scope +
"&state=" + state;
return this.Redirect(url); //performs a GET
}
For reference, here are the constants and SaveState method utilized above:
//Client and workflow values
private const string clientBaseUri = #"http://localhost:5436";
private const string validIssuer = "SomeSecureCompany";
private const string response_type = "code";
private const string grantType = "authorization_code";
//IdentityServer4
private const string idPServerBaseUri = #"http://localhost:5000";
private const string idPServerAuthUri = idPServerBaseUri + #"/connect/authorize";
private const string idPServerTokenUriFragment = #"connect/token";
private const string idPServerEndSessionUri = idPServerBaseUri + #"/connect/endsession";
//These are also registered in the IdP (or Clients.cs of test IdP)
private const string redirectUri = clientBaseUri + #"/account/oAuth2";
private const string clientId = "authorizationCodeClient2";
private const string clientSecret = "mysecret";
private const string audience = "SomeSecureCompany/resources";
private const string scope = "api";
//Store values using cookie-based authentication middleware
private void SaveState(string state)
{
var tempId = new ClaimsIdentity("TempCookie");
tempId.AddClaim(new Claim("state", state));
this.Request.GetOwinContext().Authentication.SignIn(tempId);
}
The second MVC action method is called by IdenityServer4 after the user enters their credentials and checks any authorization boxes. The action method:
Grabs the Authorization Code and State from the query string
Validates State
POSTs back to IdentityServer4 to exchange the Authorization Code for an Access Token
Here's the method:
[HttpGet]
public async Task<ActionResult> oAuth2()
{
var authorizationCode = this.Request.QueryString["code"];
var state = this.Request.QueryString["state"];
//Defend against CSRF attacks http://www.twobotechnologies.com/blog/2014/02/importance-of-state-in-oauth2.html
await ValidateStateAsync(state);
//Exchange Authorization Code for an Access Token by POSTing to the IdP's token endpoint
string json = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(idPServerBaseUri);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", grantType)
,new KeyValuePair<string, string>("code", authorizationCode)
,new KeyValuePair<string, string>("redirect_uri", redirectUri)
,new KeyValuePair<string, string>("client_id", clientId) //consider sending via basic authentication header
,new KeyValuePair<string, string>("client_secret", clientSecret)
});
var httpResponseMessage = client.PostAsync(idPServerTokenUriFragment, content).Result;
json = httpResponseMessage.Content.ReadAsStringAsync().Result;
}
//Extract the Access Token
dynamic results = JsonConvert.DeserializeObject<dynamic>(json);
string accessToken = results.access_token;
//Validate token crypto
var claims = ValidateToken(accessToken);
//What is done here depends on your use-case.
//If the accessToken is for calling a WebAPI, the next few lines wouldn't be needed.
//Build claims identity principle
var id = new ClaimsIdentity(claims, "Cookie"); //"Cookie" matches middleware named in Startup.cs
//Sign into the middleware so we can navigate around secured parts of this site (e.g. [Authorized] attribute)
this.Request.GetOwinContext().Authentication.SignIn(id);
return this.Redirect("/Home");
}
Checking that the State received is what you expected helps defend against CSRF attacks: http://www.twobotechnologies.com/blog/2014/02/importance-of-state-in-oauth2.html
This ValidateStateAsync method compares the received State to what was saved off in the cookie middleware:
private async Task<AuthenticateResult> ValidateStateAsync(string state)
{
//Retrieve state value from TempCookie
var authenticateResult = await this.Request
.GetOwinContext()
.Authentication
.AuthenticateAsync("TempCookie");
if (authenticateResult == null)
throw new InvalidOperationException("No temp cookie");
if (state != authenticateResult.Identity.FindFirst("state").Value)
throw new InvalidOperationException("invalid state");
return authenticateResult;
}
This ValidateToken method uses Microsoft's System.IdentityModel and System.IdentityModel.Tokens.Jwt libraries to check that JWT is properly signed.
private IEnumerable<Claim> ValidateToken(string token)
{
//Grab certificate for verifying JWT signature
//IdentityServer4 also has a default certificate you can might reference.
//In prod, we'd get this from the certificate store or similar
var certPath = Path.Combine(Server.MapPath("~/bin"), "SscSign.pfx");
var cert = new X509Certificate2(certPath);
var x509SecurityKey = new X509SecurityKey(cert);
var parameters = new TokenValidationParameters
{
RequireSignedTokens = true,
ValidAudience = audience,
ValidIssuer = validIssuer,
IssuerSigningKey = x509SecurityKey,
RequireExpirationTime = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
//Validate the token and retrieve ClaimsPrinciple
var handler = new JwtSecurityTokenHandler();
SecurityToken jwt;
var id = handler.ValidateToken(token, parameters, out jwt);
//Discard temp cookie and cookie-based middleware authentication objects (we just needed it for storing State)
this.Request.GetOwinContext().Authentication.SignOut("TempCookie");
return id.Claims;
}
A working solution containing these source files resides on GitHub at https://github.com/bayardw/IdentityServer4.Authorization.Code
Here's a sample - it is using hybrid flow instead of code flow. But hybrid flow is more recommended anyways if you client library supports it (and the aspnetcore middleware does).
https://github.com/IdentityServer/IdentityServer4/tree/master/samples/Quickstarts/5_HybridFlowAuthenticationWithApiAccess
Recently, I face a Azure authenticate question, the error message as follows:
Additional information: ForbiddenError: The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription.
Here is code:
private TokenCloudCredentials credentials;
public ManagerClient(TokenCloudCredentials credentials)
{
this.credentials = credentials;
}
public void GetHostedServices()
{
var computeClient = new Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient(credentials);
var services = computeClient.HostedServices.List().HostedServices;
foreach (var service in services)
{
Console.WriteLine("ServiceName: " + service.ServiceName);
Console.WriteLine("Uri: " + service.Uri);
Console.WriteLine();
}
}
public static TokenCloudCredentials GetCredentials(string subscriptionId = "")
{
var token = GetAccessToken();
if(string.IsNullOrEmpty(subscriptionId))
subscriptionId = ConfigurationManager.AppSettings["subscriptionId"];
var credential = new TokenCloudCredentials(subscriptionId, token);
return credential;
}
private static string GetAccessToken()
{
AuthenticationResult result = null;
var context = new AuthenticationContext(string.Format(
ConfigurationManager.AppSettings["login"],
ConfigurationManager.AppSettings["tenantId"]));
result = context.AcquireToken(
ConfigurationManager.AppSettings["apiEndpoint"],
ConfigurationManager.AppSettings["clientId"],
new Uri(ConfigurationManager.AppSettings["redirectUri"]));
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
return result.AccessToken;
}
var credentials = Authorizator.GetCredentials("37a80965-5107-4f9b-91c6-a1198ee40226");
new ManagerClient(credentials).GetHostedServices();
var computeClient = new Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient(credentials, new Uri("https://management.core.chinacloudapi.cn/"));
Default Uri is: https://management.core.windows.net
so China Azure need to be changed to:***/management.core.chinacloudapi.cn/