I am trying to run the Thinktecture IdentityServer v1 on my local machine. The problem is that the line
Thread.CurrentPrincipal as IClaimsPrincipal
always returns null.
Thread.CurrentPrincipal is not null, and that type of cast is often described, for example in the IClaimsPrincipal MSDN page.
I did not modify the code of the identity server, so what am I missing here?
Related
When calling a google oauth library method, it fails without error - no amount of try/catch-ing traps any error messages.
I am trying to get an identity token much as I would if I executed gcloud auth print-identity-token from the command line using the gcloud cli.
The reason for wanting the identity token is that another Cloud Function service requires it as Authorization : Bearer [token], and indeed works correctly when I stuff a manually generated identity token in my code. That is not a suitable solution for development or production
The code snippet I wrote, cobbled from numerous sources, to procure an identity token is this:
using (var stream = new FileStream(credentialsFilePath, FileMode.Open, FileAccess.Read))
{
var credentials = GoogleCredential.FromStream(stream);
if (credentials.IsCreateScopedRequired)
{
credentials = credentials.CreateScoped(scopes);
}
OidcToken oidcToken = await credentials.GetOidcTokenAsync(
Options
.FromTargetAudience(scopes[0])
.WithTokenFormat(OidcTokenFormat.Standard));
// this line bombs immediately, jumping out of this method and the calling method.
string token = await oidcToken.GetAccessTokenAsync();
return token;
}
In the above code, scopes[0] is left over code from a previous attempt which contains the endpoint to Cloud Function service. https://subdomain.cloudfunctions.net/cloud-function/v1/ is the general form of the cloud function endpoint I am calling as a part of a web api.
Is this a valid and reasonable way to get the equivalent of gcloud auth print-identity-token? If so, why the epic failure?
I need to use a google service account for service to service authentication. Development environment is visual studio 2019, .net core 3.1, docker/linux
PS - the service account has the cloud function's Cloud Functions Invoker role.
PPS - the issue seems to be related to docker and a set of error messages I get when starting my project in docker. I had ignored them as they were not until now impairing functionality.
at System.Net.Http.CurlHandler.ThrowIfCURLEError(CURLcode error)
at System.Net.Http.CurlHandler.MultiAgent.FinishRequest(StrongToWeakReference`1 easyWrapper, CURLcode messageResult)
running the code on windows works.
The penultimate problem is that I needed to make an upstream method asynchronous and add an await. Now the code above works every time. This change led me to the ultimate problem whose solution is some code refactoring in ConfigureServices() related to AddHttpClient() setup.
The curl exception was due to trying to add logger.loggerFactory.AddGoogle(…) with a bad configuration. this has been a bad hair day.
This question is also an example of what not to do - ie I used too much minimalism to describe the problem.
I have secured my API app and I have successfully tested my ADB2C flow with the sample app I found here: https://github.com/Azure-Samples/active-directory-b2c-xamarin-native. Using that structure, I can trigger the sign-in process, and then access my protected API calls.
However I wanted to also use the WindowsAzure.Mobile sdk as a convenience. It is hinted at here: https://cgillum.tech/2016/08/10/app-service-auth-and-azure-ad-b2c-part-2/ that you can trigger the B2C flow from LoginAsync in that class but it does nothing when I call it in that way.
I also found https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-dotnet-how-to-use-client-library/ (scroll to "Authenticate users with the Active Directory Authentication Library") where I substituted the MSAL calls for getting the token. This triggers the sign-on flow, I get a good token and claims back, then I put it in some JSON and pass it like so:
AuthenticationResult ar = await App.PCApplication.AcquireTokenSilentAsync(App.Scopes, "", App.Authority, App.SignUpSignInpolicy, false);
JObject payload = new JObject();
payload["access_token"] = ar.AccessToken;
user = await App.MobileService.LoginAsync(
MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
This call to LoginAsync throws
{Microsoft.WindowsAzure.MobileServices.MobileServiceInvalidOperationException: You do not have permission to view this directory or page.
at Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient+<ThrowInvalidResponse>d__18.MoveNext () [0x0022f] in <filename unknown>:0
--- End of stack trace from previous location where exception was thrown ---
(snip)
Are they not designed to work together? Are those different kinds of tokens? The reason I'm using B2C is because I really don't WANT to know all that OAUTH stuff :)
In the case of B2C, you are actually getting back an ID token instead of an access token, and I believe the ar.AccessToken property would be null. This property also seems to go away in the latest versions of MSAL.
I suspect you just need to update the payload to "authenticationToken" and instead use ar.IdToken.
I am not sure if you can continue to use the "access_token" key in the payload, but it may be that you can. If not, try "authenticationToken" instead.
I am trying to get a custom web application to work with Azure B2C OAuth and the Spring OAuth2.0 framework.
The authentication leg comes back fine and I receive a JWT token. When the request for a token occurs afterwards I get the following error:
java.lang.IllegalStateException: Access token provider returned a null access token, which is illegal according to the contract.
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:223) ~[spring-security-oauth2-2.0.8.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.0.8.RELEASE.jar:na]
...
From some debugging of the spring code I can see the token is expected to be called access_token as seen in the OAuth2AccessToken class. From looking at the B2C tutorials their token is called token_id. Furthermore the applications.yml config I have for my spring application has a field called tokenName. Surely this should be used to pick up the token name field instead of the hardcoded static variable as above.
Am I missing something and is there a solution to my problem. Can I override the token name field used by the spring OAuth framework?
I'm going to go ahead and post this as the answer.
I started with the Spring tutorial, and made some modifications to it. For a working example, see the public github repo: https://github.com/Pytry/azure-b2c-oauth2.git
To properly parse the token received you will need:
A custom implementation of an AccessToken that will parse the JWT, pulling and setting variables as required by spring security. I extended DefaultOAuth2AccessToken and added this parsing to a private method called by the constructor.
If you are going to verify the RSA signature using the public keys, you will need a custom JWT object so you can access the header information. I chose to extend springs JWT, and add some parsing on creation to access the header. It may also be useful to have some custom Pojos for parsing the returned meta data and rsakey information into.
An extension of the JwtAccessTokenConverter, with an overridden "decode" method. Azure does not give a "user_name" nor a "client_id" in the returned id_token, so you need to add those. I also included some logic in the super class that I found suefull (such as converting strings to int/long when appropriate).
A custom UserDetailsManger to override the default in memory one. This can either retrioeve user information from the GraphAPI, or it can load it from your user repository. I actually did not create either of these, and instead used the default in memory service, but injected it into the token converter; then whenever a user was properly authenticated, I would add them to the managers store, or update them if they already existed.
There are a few things I have not done yet.
RSA verification is not being done. Any help on this is appreciated.
I know what is the concept of OAuth: User sends request to the server with grant type, username and password, after some checks on server, the user receives an access token.
What I cannot understand is why I should do this:
ClaimsIdentity oAuthIdentity = await _userManager.CreateIdentityAsync(user,
context.Options.AuthenticationType);
var ticket = new AuthenticationTicket(oAuthIdentity, GenerareProperties(user));
context.Validated(ticket);
What is CreateIdentityAsync returning? What is an AuthenticationTicket? What does context.Validated do?
Also, If I have oAuthIdentity why should I also use cookiesIdentity? And finally, where is the access token being generated?
I searched but cannot find a website that explains this.
CreateIdentityAsync Will return the ClaimsIdentity to be used in the ClaimsPrincipal of the running context, which is further abstracted in...
An AuthenticationTicket is just a packaging of exactly what is passed in, for convenience.
context.Validated will add the information in the ticket to the current principal, and allow the OWIN pipeline to continue instead of returning a 401.
The reason for the cookiesIdentity is to allow authentication from the MVC pages in the template. It really is not used for the WebApi.
Some Sources for further reading:
Here is a nice article that describes the template from the RC, which was similar
Also here are two blogs where their authors break down parts of .NET security that might seem obscure
G'day everybody!
I've got error like this:
WARN/DefaultRequestDirector(22739): Authentication error: Unable to respond to any of
these challenges: {authsub=WWW-Authenticate: AuthSub
realm="https://www.google.com/accounts/AuthSubRequest" allowed-
scopes="https://www.googleapis.com/auth/userinfo.email,
https://www.googleapis.com/auth/userinfo.profile,
https://www.googleapis.com/auth/userinfo.id"}
It's happend when I wanna get connection:
AccessGrant accessGrant = new AccessGrant(accessToken);
Connection<Google> connection = connectionFactory.createConnection(accessGrant);
As the result, I catch exception as Auth 401.
Did any one that problem befor?
It looks like you are using the old AuthSub authentication when you should be using OAuth2 authentication. I suggest you take a look at the example application, specifically see in SocialConfig how to create ProviderSignInController which is used for sign in.
I've found why it was happened. The problem was in scope. I set only https://www.googleapis.com/auth/plus.me scope. It wasn't enough for create connection.
As result, I had the next message:
WARN/DefaultRequestDirector(22739): Authentication error: Unable to respond to any of
these challenges: {authsub=WWW-Authenticate: AuthSub
realm="https://www.google.com/accounts/AuthSubRequest" allowed-
scopes="https://www.googleapis.com/auth/userinfo.email,
https://www.googleapis.com/auth/userinfo.profile,
https://www.googleapis.com/auth/userinfo.id"}
As you can see google oauth2 asks for https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile, https://www.googleapis.com/auth/userinfo.id scopes.
After I had added this scopes and I got a new error likes "invalid_scope".
Problem was in connection url.
I created connection url as:
connectionFactory.getOAuthOperations().buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, params);
where params:
OAuth2Parameters params = new OAuth2Parameters();
params.setRedirectUri(redirectUri);
params.setScope("https://www.googleapis.com/auth/userinfo.email+" + "https://www.googleapis.com/auth/userinfo.profile+" + "https://www.googleapis.com/auth/userinfo.id+" +
"https://www.googleapis.com/auth/plus.me");
In this case, symbol "+" was decoded to another one and Google oauth2 api couldn't recognize scope set.
I hope this solution will help somebody in future.