We're struggling with an issue during the token verification. We have the following exception:
java.security.SignatureException: Invalid audience: xxx-platform. Should be: 787384428332-32charsofidxxxxxxxx.apps.googleusercontent.com
at com.google.identitytoolkit.JsonTokenHelper$AudienceChecker.check(JsonTokenHelper.java:67)
at net.oauth.jsontoken.JsonTokenParser.verify(JsonTokenParser.java:156)
at net.oauth.jsontoken.JsonTokenParser.verify(JsonTokenParser.java:103)
at net.oauth.jsontoken.JsonTokenParser.verifyAndDeserialize(JsonTokenParser.java:116)
at com.google.identitytoolkit.JsonTokenHelper.verifyAndDeserialize(JsonTokenHelper.java:46)
at com.google.identitytoolkit.GitkitClient.validateToken(GitkitClient.java:126)
at com.google.identitytoolkit.GitkitClient.validateTokenInRequest(GitkitClient.java:154)
at com.some.package.user.GitKitUserService.getGitkitUserFromRequest(GitKitUserService.groovy:25)
We have checked many times the gitkit-server-config.json file, he seems to correct and points to a valid .p12 file. The p12 is correctly found and opened (since we have a FileNotFoundException when we remove it, or parsing error when we alter it...) but the validation fails because of a null verifier...
Here it is:
{
"clientId": "707385568332-32charsofidxxxxxxxx.apps.googleusercontent.com",
"projectId": "xxx-platform",
"serviceAccountEmail": "xxx#xxx-platform.iam.gserviceaccount.com",
"serviceAccountPrivateKeyFile": "/an/existing/path/xxx-platform-44d0379d237c.p12",
"widgetUrl": "https://example.com/authentication/authenticate",
"cookieName": "gtoken"
}
Of course we can provide any additional information that might be required, we're really stuck with this issue!
Thank in advance for any clue!
I think DFB's answer is correct.
But we don't recommend hard-coded json config in Java code. There's a static method called createFromJson you can use to read json file and then initialize GitkitClient.
We'll also need to update the README in identity-toolkit-java-client. Thanks for your question.
I'll just share my experience from setting up earlier today incase it can help you:
String token = cookie.getValue();
try {
GitkitClient gitkitClient = GitkitClient.newBuilder()
.setGoogleClientId("206268081687-u5mg1cl3teeeo635vrsuj8uotdi7meqq.apps.googleusercontent.com")
//.setGoogleClientId("effortless-edge-119904")
.setServiceAccountEmail("tables#effortless-edge-119904.iam.gserviceaccount.com")
.setCookieName("gtoken")
.setWidgetUrl("http://localhost:8080/gitkit")
.setKeyStream(new ClassPathResource("tables-8271416a8e0c.p12").getInputStream()).build();
GitkitUser gitkitUser = gitkitClient.validateToken(token);
Gives me
java.security.SignatureException: Gitkit token audience(effortless-edge-119904)
doesn't match projectId or clientId in server configuration
This works:
try {
GitkitClient gitkitClient = GitkitClient.newBuilder()
.setGoogleClientId("effortless-edge-119904")
.setServiceAccountEmail("tables#effortless-edge-119904.iam.gserviceaccount.com")
.setCookieName("gtoken")
.setWidgetUrl("http://localhost:8080/gitkit")
.setKeyStream(new ClassPathResource("tables-8271416a8e0c.p12").getInputStream()).build();
GitkitUser gitkitUser = gitkitClient.validateToken(token);
logger.info("Validated gitkit token");
I was getting the same error and stumbled upon this thread. I was using gitclient-1.2.3.jar. I updated it to gitkitclient-1.2.5.jar (latest) and the problem went away.
UPDATE: I'm adding the code snippet below. I'm setting both setGoogleClientId and setProjectId as shown in the sample https://github.com/google/identity-toolkit-java-client/blob/master/src/main/java/com/google/identitytoolkit/GitkitClient.java
GitkitClient gitkitClient = new GitkitClient.Builder()
.setGoogleClientId("654028407702-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com")
.setProjectId("my-project")
.setServiceAccountEmail("my-project#my-project.iam.gserviceaccount.com")
.setKeyStream(context.getResourceAsStream("/WEB-INF/identity/my-project-xxxxxxxxxxxx.p12"))
.setWidgetUrl("https://my-project.appspot.com/oauth2callback")
.setCookieName("gToken")
.setServerApiKey("AIzaSyAxQ7z5Dxxxxxxxxxxxxxx-xxxxxxxx")
.build();
I had a look at the gitkitclient.js source code and both projectId and clientId are added to the same audiences array.
After more tests I found out that you must only put the project ID ('my-project-name') in the gitkit-server-config.json file.
The nasty thing is that if you add it with a 'clientId' property name it is also working...
As far as I can see, the client ID (like 654028407702-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com) can be removed.
Related
Im learning Firebase with Unity and using the RestClient and while it worked well with just reading and writing to the database, in the authentication part Im stuck, I have only tested the signup part so far but it gives me error http unknown, I got the url from the reference docs in firebase site, here is the function that throws the error in case it helps but I assume I got the url wrong or something, Im open to any solution you give, thanks =) :
void signUpUser(string nombreusuario,string email, string password)
{
string datosusuario="{\"email\":\""+email+"\",\"password\":\""+password+"\",\"returnSecureToken\":true}";
RestClient.Post<signresponse>("https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=" + AuthKey, datosusuario).Then( ResponseHelper=>
{
localId = ResponseHelper.localId;
idToken = ResponseHelper.idToken;
nombre = nombreusuario;
enviaBaseDatos(true);
}).Catch(error=>
{
Debug.Log(error);
});
}
So I've been digging and I think that documentation is partially wrong as it says that the endpoint is
https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]
But It also says
You can create a new email and password user by issuing an
HTTP POST request to the Auth signupNewUser endpoint.
So the real endpoint is signUpNewUser instead of simply signUp!
https://identitytoolkit.googleapis.com/v1/accounts: signUpNewUser?key=[API_KEY]
If this new endpoint does not work, try the version 3 of the endpoint:
https://www.googleapis.com/identitytoolkit/v3/relyingparty/signUpNewUser?key=[API_KEY]
trying to use Azure AD as OpenID provider with IdentityModel package
However the problem is that it produces wrong endpoint configuration
var client = new HttpClient();
const string identityUrl = "https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/v2.0";
const string restUrl = "https://localhost:44321";
var disco = await client.GetDiscoveryDocumentAsync(identityUrl);
if (disco.IsError)
{
Console.WriteLine(disco.Error);
return;
}
returns error
Endpoint belongs to different authority:
https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/authorize
openid-configuration output is
{"authorization_endpoint":"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/authorize",
"token_endpoint":"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/token" ... }
oauth2 is added between the tenatID and version. I suppose this is why openid metadata validation fails.
Is it possible to configure AzureAD to return correct metadata for the openid-configuration ?
Regards
could you find a solution for this? The only way I could figure out (far to be the optimal solution) is to add the endpoints to a list of additional endpoint base addresses. Otherwise you have to set the validations to false as stated in the comments above.
var client = httpClientFactory.CreateClient();
var disco = await client.GetDiscoveryDocumentAsync(
new DiscoveryDocumentRequest
{
Address = "https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/v2.0",
Policy =
{
ValidateIssuerName = true,
ValidateEndpoints = true,
AdditionalEndpointBaseAddresses = { "https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/token",
"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/authorize",
"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/discovery/v2.0/keys",
"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/devicecode",
"https://graph.microsoft.com/oidc/userinfo",
"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/logout"
}
},
}
);
If you take a look at the code inside IdentityModel repository, you can see that the default validation of the endpoints validates them by doing a "starts with" method. https://github.com/IdentityModel/IdentityModel/blob/1db21e2677de6896bc11227c70b927c502e20898/src/Client/StringComparisonAuthorityValidationStrategy.cs#L46
Then the only two required AdditionalEndpointBaseAddresses inside the DiscoveryDocumentRequest Policy field you need to add are "https://login.microsoftonline.com/<guid>" and "https://graph.microsoft.com/oidc/userinfo".
I had the same problem as well and when i upgraded IdentityModel to version 2.16.1 the problem was solved
Azure AD seems to need Additional Endpoints configuration as #flacid-snake suggested. Setting validate endpoints to False is a security threat and should be avoided.
The best way is to make it configurable, preferable in the UI when you configure the SSO server. Endpoints can change and they should be easy to change. It will also make it easier if you later decide to support Okta or other providers and they require additional endpoints.
As of June 2021 you also need to include Kerberos endpoint like:
https://login.microsoftonline.com/888861fc-dd99-4521-a00f-ad8888e9ecc8bfgh/kerberos (replace with your directory tenant id).
So I have an Angular app that uses the adal-angular library to authenticate with an ASP.NET Core 2.0 Web API. The API then uses on-behalf-of flow to authenticate with another API using the users token like this MS article https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-on-behalf-of.
The issue I have is this is working fine in the DEV environment but I have now deployed a TST environment with separate App Registrations and I am receiving the following exception when I try and request the token using on-behalf-of
AADSTS240002: Input id_token cannot be used as 'urn:ietf:params:oauth:grant-type:jwt-bearer' grant.
The code I am using to request the token
public async Task<string> AcquireTokenAsync(string resource)
{
try
{
string accessToken = await _httpContextAccessor.HttpContext.GetTokenAsync(AuthenticationConstants.AccessToken);
var credentials = new ClientCredential(_azureOptions.ClientId, _azureOptions.ClientSecret);
var authContext = new AuthenticationContext($"{_azureOptions.Instance}{_azureOptions.TenantId}")
{
ExtendedLifeTimeEnabled = true
};
// On-behalf-of auth token request call
var authResult = await authContext.AcquireTokenAsync(
resource,
credentials,
new UserAssertion(accessToken));
return authResult.AccessToken;
}
catch (AdalServiceException asex)
{
_logger.LogError(asex, $"Instance: {_azureOptions.Instance} Tenant: {_azureOptions.TenantId} ClientId: {_azureOptions.ClientId}");
throw;
}
catch (System.Exception ex)
{
_logger.LogError(ex, ex.Message);
throw;
}
}
And I have used Fiddler and it looks like all the correct parameters are being passed.
Any help would be very much appreciated. I have set knownClientApplications on the second API and I have granted permissions on the Angular backend API to the second API.
For me, I got it to work by changing BOTH of the following to true:
oauth2AllowImplicitFlow
oauth2AllowIdTokenImplicitFlow
See here for more information.
According to your question and the error, it should be caused by that you angular app is not a Native(public) app.
For using this OBO flow with this Grant type, your client must be a public client not credential client.
If you want to register your client as a WebApp/API, you can refer to this Implementation:
Hope this helps!
Update
According to OP's comment, he/she got it working by changing oauth2AllowImplicitFlow from false to true.
We had this problem last week with one Azure Service Registration and not another. A review found that the token didn't return an AIO being returned. It turns out that the registration had redirects with wildcards (e.g., https://*.ngrok.io) and this is incompatible with the AcquireTokenOnBehalfOf function. I'm posting this here so a future person, probably me, will find it.
I was having problems even when oauth2AllowImplicitFlow and oauth2AllowIdTokenImplicitFlow were set to true. One of my Reply URLs had a wildcard in it. When the wildcard was removed, the issue was resolved.
I tried to enhance my existing WebApi with IdentityServer3. So I installed the IdentityServer3.AccessTokenValidation package and added this piece of code to my Startup Configuration
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "<myIdentityServerUrl>",
ValidationMode = ValidationMode.ValidationEndpoint,
RequiredScopes = new[] { "api1" }
});
(I did not apply the AuthorizeAttribute filter, so I can see what's going on).
The identity server so far is the exact same as in the docs (code here). I tried to debug-call the test service and I saw that this.User (in the controllers method) was null. So I looked into the RequestContext. Now that was weird:
RequestContext.Principals is null
RequestContext.Request.Headers.Authorization has the correct access_token
As far as I know even if I made a mistake with the scopes or Authority -what I highly doubt- I should still get the claims. The AuthorizeAttribute would probably return an Unauthorized http message but that doesn't matter because I did not add that filter yet.
EDIT: The question is about why using setAutoCommit(false) is a solution for the "there is no active transaction" exception. Forget this question since this is not the correct solution (at least in my case). I will leave the question here in case somebody encounters the same problem. See my answer below for more details.
================
The following code worked fine in Symfony 2.7, but after an update to Symfony 2.8 (and to the latest DoctrineBundle version), a There is no active transaction exception is thrown:
private function getSynchronization() {
$lock_repo = $this->entityManager->getRepository('MyAppBundle\Entity\DBLock');
$this->entityManager->getConnection()->beginTransaction();
try {
$sync = $lock_repo->findOneByUser($this->getUser());
if (!$lock) {
$lock = new DBLock();
} else {
if ($lock->isActive()) {
// ... Exception: Process already running
}
$expected_version = $lock->getVersion();
$this->entityManager->lock($lock, LockMode::OPTIMISTIC, $expected_version);
}
$sync->setActive(false);
$this->entityManager->persist($sync);
$this->entityManager->flush();
$this->entityManager->getConnection()->commit();
// EXCEPTION on this line
$this->entityManager->lock($lock, LockMode::NONE);
}
catch(\Exception $e) {
$this->entityManager->getConnection()->rollback();
throw new ProcessException($e->getMessage());
}
...
}
After some searching I found a solution in another post. After adding the following line everything works fine:
private function getSynchronization() {
$lock_repo = $this->entityManager->getRepository('MyAppBundle\Entity\DBLock');
$this->entityManager->getConnection()->beginTransaction();
// ADDED LINE
$this->entityManager->getConnection()->setAutoCommit(false);
try {
...
So, the question is not how to solve the problem, but how the solution works...
I am quite confused by the Doctrine docs of the setAutoCommit() method:
To have a connection automatically open up a new transaction on
connect() and after commit() or rollBack(), you can disable
auto-commit mode with setAutoCommit(false)
I do not understand this.
Does this mean, that the transaction that was started/created with beginTransaction() is now automatically closed when using commit()? So in order to be able to use lock(...) after using commit() I have to begin a new transaction first. I can either do this manually by calling beginTransaction() again, or auotmatically by setting setAutoCommit(false) before. Is that correct?
Is this a change in on of the latest Doctrine versions? I did not found anything about in in the updates notes and before the update of Symfony/Doctrine the code worked just fine.
Thank you very much!
As described before I encountered the problem, that calling lock($lock, LockMode::NONE) suddenly threw a There is no active transaction exception after the Update from Doctrine 2.4 to 2.5.
My solution was to add setAutoCommit(false), which automatically created a new transaction after calling commit(). It worked and the exception did not occur again. However, this is not the real/correct solution, it creates other problems as side effects.
After re-reading the Doctrine Update Notes I found out, that the correct solution is to use lock($lock, null) instead of lock($lock, LockMode::NONE). This is BC Break between Doctrine 2.4 and 2.5.
Maybe my question and answer helps someone else who encounters the same problem.