I followed the following guide to setup a JHipster generated Gateway with Amazon Cognito: https://blog.ippon.tech/aws-cognito-and-jhipster-for-the-love-of-oauth-2-0/
I got the gateway working great and I'm able to log in into the admin module using Cognito however I am not able to invoke any of the microservices. Any attempt is met with the following error:
java.lang.NullPointerException: null at
com.test.security.oauth2.AudienceValidator.validate(AudienceValidator.java:26)
at
com.test.security.oauth2.AudienceValidator.validate(AudienceValidator.java:13)
at
org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator.validate(DelegatingOAuth2TokenValidator.java:67)
at
org.springframework.security.oauth2.jwt.NimbusJwtDecoder.validateJwt(NimbusJwtDecoder.java:165)
at
org.springframework.security.oauth2.jwt.NimbusJwtDecoder.decode(NimbusJwtDecoder.java:126)
at
org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider.authenticate(
Debugging show that audience variable is null in the following code:
public OAuth2TokenValidatorResult validate(Jwt jwt) {
List<String> audience = jwt.getAudience();
if (audience.stream().anyMatch(allowedAudience::contains)) {
return OAuth2TokenValidatorResult.success();
} else {
log.warn("Invalid audience: {}", audience);
return OAuth2TokenValidatorResult.failure(error);
}
}
I've configured the microservice's application.xml with the following:
security:
oauth2:
client:
provider:
oidc:
issuer-uri: https://cognito-idp.us-east-1.amazonaws.com/[secret]
registration:
oidc:
client-id: [secret]
client-secret: [secret]
Has anyone been able to successfully run a jHipster generated microservices platform with Amazon Cognito? Any help would be greatly appreciated.
AWS Cognito doesn't include the audience in the access token so the validate methods must be updated.
More details can found here: https://github.com/Falydoor/cognito-jhipster/issues/1#issuecomment-594753033
Related
I generated a gateway application with JHipster to test oauth2 through Okta for my organization. I didn't make any changes to the code beyond what was recommended in the readme: The client ID and Secret are in the yml, as well as the issuer uri.
It redirects me to Okta. I log in. It redirects back as expected. Then I got an unauthorized error at /login?error. So I tried adding a permitAll for /login/**. This resulted in error 404.
Something in the recommended configuration is not working as expected.
application.yml:
oauth2:
client:
provider:
oidc:
issuer-uri: https://dev-[numbers].okta.com/oauth2/default
registration:
oidc:
client-id: {my real client id}
client-secret: {my client secret}
scopes:
- profile
- email
- openid
- customScope
What am I doing wrong?
Could it be the environment variables are not being read?
From .okta.env, but I also added them to the environment variables in the intellij configuration
export SECURITY_OAUTH2_CLIENT_USER_AUTHORIZATION_URI="https://dev-[number].okta.com/oauth2/default/v1/authorize"
export SECURITY_OAUTH2_RESOURCE_USER_INFO_URI="https://dev-[number].okta.com/oauth2/default/v1/userinfo"
export SECURITY_OAUTH2_RESOURCE_TOKEN_INFO_URI="https://dev-[number].okta.com/oauth2/default/v1/introspect"
export SECURITY_OAUTH2_CLIENT_CLIENT_ID={clientid}
export SECURITY_OAUTH2_CLIENT_CLIENT_SECRET={clientsecret}
I am trying to use MSAL to add SSO for my single page app, for the purpose of getting an Oauth2 token to be used for resolving a Microsoft SaaS subscription. I have configured my code based on this sample repo: https://github.com/Azure-Samples/ms-identity-javascript-v2. This uses MSAL 2.0, instead of 1.X versions.
Here is the relevant code snippet, ran on the /signup page:
var config = {
auth: {
clientId: <MY_CLIENT_ID>,
authority: "https://login.microsoftonline.com/common",
redirectUri: <APP_URL> + "/signup",
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: false,
}
};
var msalInstance = new msal.PublicClientApplication(config);
msalInstance.loginPopup(["openid", "profile", "User.Read"]).then((response) => {
console.log(response)
}).catch(error => {
console.error(error);
});
Calling this code inside my application, I successfully log in using the popup window, but get the following error: ServerError: invalid_client: 70002 - [2020-09-03 16:55:35Z]: AADSTS70002: The provided request must include a 'client_secret' input parameter.
I can see the underlying network call is https://login.microsoftonline.com/common/oauth2/v2.0/token with the following form data:
client_id: <MY_CLIENT_ID>
redirect_uri: <APP_URL>/signup
scope: openid profile
code: <some value>
code_verifier: <some value>
grant_type: authorization_code
client_info: 1
client-request-id: <some value>
Based on the documentation here https://learn.microsoft.com/en-us/advertising/guides/authentication-oauth-identity-platform?view=bingads-13#request-accesstoken, this call should have a configurable client_secret parameter, which results in the error I am getting I believe.
I have the required client secret from my App on Azure Portal. My question is, how can I configure the client secret in my config object? I have not been able to find any examples online, as well I tried adding clientSecret as a key under auth inside my config blindly, this did not pass it to the login.microsoftonline.com call.
UPDATE
After a bit more digging around, I realized the underlying issue of my setup was that I was trying to use the authorization grant flow to request a token but needed to use the client credentials flow. After moving the token acquisition to the backend (and using the client secret there), and some more help in this followup thread I was able to get SSO and token acquisition working as expected.
Instead of creating Web create Single-page-application this will solve you problem. See the example below
We have debugged your sample and we are able to use it with out any issue. After testing we believe the issue is occurring sine your code is not able to call Signin() method in '/authPopup.js'.You will not face any issue if this method call happens in your index.html.
Instead of using MSAL directly, consider looking into using the new SSO capabilities inside Teams - it wraps a lot of this for you and makes it easier to use. Here's an overview and here is a working sample.
Regarding the sample, it's in node, and I'm working on a dotnet version of the same. It looks like you use node, so you should rather refer to the original, but I think I found a few bugs so you can look at the client-side script in my version if you run into any issues - see here.
I'm trying to secure my aspnet core web API server by making it authenticate against Azure B2C using user-provided JWT bearer tokens. I've followed some sample code found on official microsoft github pages, but can't seem to get it working.
In my B2C policy, I've got it set to use the default issuer URL format: https:////v2.0/
In my web application, I've got that same URL specified as the Authority in the JWT options.
When I submit an HTTP request to my server, the identity server code fails as it tries to reach out to B2C to fetch the openid-configuration. It fails with the following error ...
HttpRequestException: Response status code does not indicate success: 404 (Not Found).
System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
IOException: IDX20804: Unable to retrieve document from: 'https://innovativelitfoundry.b2clogin.com/0f55bfb6-6af5-4293-8963-29ae099183cc/v2.0/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string address, CancellationToken cancel)
InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://innovativelitfoundry.b2clogin.com/0f55bfb6-6af5-4293-8963-29ae099183cc/v2.0/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.ConfigurationManager<T>.GetConfigurationAsync(CancellationToken cancel)
Indeed, that URL will not work because it does not appear to be including the policy name, from the used token, in the query string. So, that URL does indeed not work.
I'm unsure how to make the code provide that policy name in the query string, though? Or should it be doing that automatically?
Here is the code, in my aspnet core web api application, where I configure the authentication settings ...
public void ConfigureServices(IServiceCollection services)
{
IdentityModelEventSource.ShowPII = true;
services
.AddAuthentication(ConfigureAuthentication)
.AddJwtBearer(ConfigureJwt);
services
.AddCors();
services
.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services
.AddSingleton(Configuration);
}
private void ConfigureAuthentication(AuthenticationOptions options)
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}
private void ConfigureJwt(JwtBearerOptions options)
{
var tenant = Configuration["AzureAd:TenantId"];
options.Audience = Configuration["AzureAd:ApplicationId"];
options.Authority = $"https://innovativelitfoundry.b2clogin.com/{tenant}/v2.0/";
}
Does anybody perhaps know what I may be doing incorrectly here? How can I get my aspnet core web api application to correctly pull down that openid configuration document?
You must set options.Authority to an authority URL that includes the policy ID:
options.Authority = $"https://innovativelitfoundry.b2clogin.com/{tenant}/{policy}/v2.0/";
As long as you have set the issuer claim for all policies to the issuer URL that doesn't contain the policy ID, then your API application can download the configuration document for any policy and then validate tokens that are issued for all policies.
I am trying to protect my backing services to my frontend webapp using MSI and AAD auth.
I keep getting a 401 when I call my backing services form the public facing webapp. I have added the public webapp as a reader in the IAM section of the backing services.
What I can't figure out is how to obtain the access token, it seems that no matter which endpoint I use for obtaining the access token, it says that it is not found.
Here is my code:
{
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://<mywebapi>.azurewebsites.net").GetAwaiter().GetResult();
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", accessToken);
RemoteIp = httpClient.GetStringAsync("https://<mywebapi>.azurewebsites.net/api/default/remoteIp").GetAwaiter().GetResult();
LocalIp = httpClient.GetStringAsync("https://<mywebapi>.azurewebsites.net/api/default/localIp").GetAwaiter().GetResult();
ConnectionId = httpClient.GetStringAsync("https://<mywebapi>.azurewebsites.net/api/default/connectionId").GetAwaiter().GetResult();
}
And here is the error message:
Parameters: Connectionstring: [No connection string specified], Resource: https://<mywebapi>.azurewebsites.net, Authority: .
Exception Message: Tried to get token using Managed Service Identity.
Unable to connect to the Managed Service Identity (MSI) endpoint.
Please check that you are running on an Azure resource that has MSI setup.
UPDATE:
<mywebapi> is obviously the actual endpoint value, but not exposed here on stackoverflow. Furthermore I should mention that calling the API endpoints directly works fine, after I have authorized with my personal credentials xxx#xxx.xxx. The issue is related to the webapp trying to identify itself to the webapi, even though it is a registered application which has been assigned the necessary IAM rights on the webapi resource.
The error says it tried to use MSI, but could not. Are you sure you are running this code on the Web App with MSI enabled?
Also, you need to replace "https://<mywebapi>.azurewebsites.net" with the App Id URI or Application Id of your API in Azure AD.
In other words, this needs to match the valid audience that you have configured for the API.
I'm trying to use the swagger node to build an API to my meteor app. I managed to build the API but could not find a good guide on how to secure it. The plan is to let our mobile app connect to the main app in the server. (For this we also need to generate device-specific keys right?)
So far we tried to setup security in swagger like this :
securityDefinitions:
oauth2:
type: oauth2
authorizationUrl: "http://swagger.io/api/oauth/dialog"
flow: "implicit"
security:
- oauth2: []
But it gave us this error:
{
"message": "unknown security handler: oauth2",
"code": "server_error",
"statusCode": 403
}
Can you please tell me why the error is coming and how to properly implement the API according to my needs? Thanks!