App registration on localhost or own domain - shopware

I am developing a Shopware 6 app and I have encountered my first issue during the registration. When I click install, I get the error Could not sign payload with store secret for app: app_name. The registration request never even reached the app server, because this error prevented the registration request from being sent.
After some more digging I came across two other clues:
An exception Shopware\Core\Framework\Store\Exception\ShopSecretInvalidException (Error message: Store shop secret is invalid)
The response from the Shopware platform that caused the exception to be thrown:
{
"success": false,
"code": "ShopwarePlatformException-68",
"title": "Invalid shop authentication",
"description": "The action performed is not allowed because the shop is not uniquely authenticated. Try to reconnect the Shopware account under \"My extensions\". If the error still occurs, please contact our customer service",
"documentationLink": "https://docs.shopware.com/en/shopware-6-en/settings/extensions/error-messages#invalid_shop_authentification",
"status": 401,
"detail": "INVALID_SHOP_AUTHENTICATION",
"context": []
}
This was already actionable info, so I went to the "My extensions" tab and tried to log in with my Shopware account. I got another error: Licensing host unknown.
I have tried and failed on two Shopware instances - one on localhost, one on a domain which I had connected to my Shopware Account as a wildcard environment. I also tried adding the same domain to "Shops in the partner account", but I got an error saying that the domain was already registered. I assume this is because the domain is already registered as a wildcard domain.
So, my question is twofold at this point:
Is it possible to somehow circumvent this signature mechanism in order to be able to develop and test the app locally?
What do I need to do on my Shopware Account in order to be able to log in to my account on a Shopware instance hosted on a regular domain?

For development purposes you can use a private app initially. You'll have to provide in a secret in your manifest.xml in that case.
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/platform/master/src/Core/Framework/App/Manifest/Schema/manifest-1.0.xsd">
<!-- ... -->
<setup>
<registrationUrl>http://localhost/register/</registrationUrl>
<secret>verysecret</secret>
</setup>
</manifest>
Minimal example of handling the registration request on your app server:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
$request = Request::createFromGlobals();
$query = $request->query->all();
$proof = \hash_hmac(
'sha256',
$query['shop-id'] . $query['shop-url'] . 'YourAppName',
'verysecret'
);
$response = new JsonResponse([
'proof' => $proof,
'secret' => 'verysecret',
'confirmation_url' => 'http://localhost/confirm/'
]);
$response->send();

Related

azure .net core app with IS4: web api call fails with "Bearer error=invalid_token The issuer is invalid"

I have a .net Core 3.1 app running in an azure web app for containers(linux) service. This app is a web api project with an angular 9 front end. It uses Identity server 4 for authorization.
For reference I am using this clean architecture framework template for my project (the add docker support pr).
The app runs in the service just fine. The front end works and I can "log in" using ID4 and I can see that the authorization token are returned when I log in.
THE PROBLEM:
When I make a call to the backend web api from the front end angular client app I get the following error:
HTTP/1.1 401 Unauthorized
Server: Kestrel
WWW-Authenticate: Bearer error="invalid_token", error_description="The issuer 'https://*********.azurewebsites.net' is invalid"
I am tempted to add a manual setting for the IssuerUri but the identity server 4 docs recommend against doing this so I did not. Maybe having this run in docker makes it different.
I did have to add support for forwarding headers to get IS4 to work properly in startup.cs configureServices according to these docs for proxy load balancers. I had to add ASPNETCORE_FORWARDEDHEADERS_ENABLED=true to my application settings
When I compare fiddler results for the requests, I can see that the AspNetCore.Antiforgery is the same for login and web api calls but the .AspNetCore.Identity.Application value is different.
I am using nSwag to auto generate api service calls for angular if that makes a difference.
QUESTION:
can someone help me figure out why I can login but all web api requests fail with the unauthorized error above?
thanks in advance.
JK
EDIT 1
I used fiddler to get the authorization token for the request and used jwt.io to parse it. The iss value was the same as the app/web api:
"iss": "https://******.azurewebsites.net",
IS4 used this domain to log in and that worked properly. If that value is correct, is there another thing that might be wrong?
EDIT 2:
Just for more context.
My app uses in statup.cs Configure:
app.UseHsts();
app.UseHttpsRedirection();
As a result I needed to add the following code to make sure the headers get forwarded in the requests between app service's handling of the TSL, load balancer/proxy and my docker container (starup.cs ConfigureServices):
// the following is documented here:
// https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1#forward-the-scheme-for-linux-and-non-iis-reverse-proxies-1
// it is needed to run kestrel in azure app service in http with header forwarding
if (string.Equals(
Environment.GetEnvironmentVariable("ASPNETCORE_FORWARDEDHEADERS_ENABLED"),
"true", StringComparison.OrdinalIgnoreCase))
{
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
// Only loopback proxies are allowed by default.
// Clear that restriction because forwarders are enabled by explicit
// configuration.
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
}
I get the following error in the logs which confirm the same error above as an Issuer mismatch
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException:
IDX10205: Issuer validation failed. Issuer: '[PII is hidden. For more
details, see https://aka.ms/IdentityModel/PII.]'. Did not match:
validationParameters.ValidIssuer ...
I am using the following default setup for the Jwt token:
services.AddAuthentication().AddIdentityServerJwt();
If i navigate to the https://*******.azurewebsites.net/.well-known/openid-configuration/jwks I get the following JSON setting for my OIDC setup:
{
"issuer": "https://*******.azurewebsites.net",
"jwks_uri": "https://*******.azurewebsites.net/.well-known/openid-configuration/jwks",
"authorization_endpoint": "https://*******.azurewebsites.net/connect/authorize",
"token_endpoint": "https://*******.azurewebsites.net/connect/token",
"userinfo_endpoint": "https://*******.azurewebsites.net/connect/userinfo",
"end_session_endpoint": "https://*******.azurewebsites.net/connect/endsession",
"check_session_iframe": "https://*******.azurewebsites.net/connect/checksession",
"revocation_endpoint": "https://*******.azurewebsites.net/connect/revocation",
"introspection_endpoint": "https://*******.azurewebsites.net/connect/introspect",
"device_authorization_endpoint": "https://*******.azurewebsites.net/connect/deviceauthorization",
"frontchannel_logout_supported": true,
"frontchannel_logout_session_supported": true,
"backchannel_logout_supported": true,
"backchannel_logout_session_supported": true,
"scopes_supported": [
"openid",
"profile",
"CleanArchitecture.WebUIAPI",
"offline_access"
],
"claims_supported": [
"sub",
"name",
....
"updated_at"
],
"grant_types_supported": [
"authorization_code",
"client_credentials",
"refresh_token",
"implicit",
"password",
"urn:ietf:params:oauth:grant-type:device_code"
],
"response_types_supported": [
"code",
"token",
"id_token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"response_modes_supported": ["form_post", "query", "fragment"],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"id_token_signing_alg_values_supported": ["RS256"],
"subject_types_supported": ["public"],
"code_challenge_methods_supported": ["plain", "S256"],
"request_parameter_supported": true
}
I compared the Issuer in this document and they are the same as the one in the token as shown decoded above.
I am still not sure how to debug this to figure out where the issuer mismatch is happening.
NOTE: I have narrowed this down a bit. All calls to the built in/default IS4 endpoints work. Its only the custom webAPI endpoints I define in my controllers that are not validating the token properly.
Any webAPI endpoint with [Authorize] attribute fails with invalid issuer
EDIT 3:
Thanks to #d_f comment I used the IS4 docs for adding local API
I added the following call to my services initialization in startu.ca configure services:
services.AddIdentityServer().AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddLocalApiAuthentication(); // I added this line after the above line
I then changed the [Authorize] attribute at the top of my webAPI controller to:
//[Authorize]
[Authorize(IdentityServerConstants.LocalApi.PolicyName)]
However, I am still getting the same error. Only on my custom webAPI endpoints, the IS4 endpoints all work. Login works but not any web api endpoints that have [Authorize] attribute.
EDIT 4:
I removed the above settings and chnaged my services.AddAUthentication() to the following:
services.AddAuthentication()
.AddIdentityServerJwt()
.AddLocalApi(options =>
options.ExpectedScope = "IdentityServer4");
I also tried:
services.AddAuthentication()
.AddIdentityServerJwt()
.AddLocalApi();
I used the policy name "IdentityServer4" because it appears to be a default policy within IS4
Here is what the full context looks like:
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt()
.AddLocalApi(options =>
options.ExpectedScope = "IdentityServer4");
This works locally on my machine with all these variations. Its just when run inside container in azure web app that I get the issuer failure for my custom webAPI endpoints.
SOLUTION:
I found a solution thanks to all the help here. IS4 out of the box attempts to set the ISS / Issuer automatically. This works locally but in my production environment my container run in azure web apps for containers. Azure places my container inside of another container for load balancing/proxy to handle the https encryption as well. As a result there is a difference between the auto detected IS4 issuer in my container and the azure web app URL.
By manually setting the issuer in my code the error went away and everything works.
You can do this in two places
in your appsettings.jsson like:
"IdentityServer": {
"IssuerUri": "https://yourapp.azurewebsites.net",
or in code like this:
services.AddIdentityServer(options =>
{
options.IssuerUri = "https://your.azurewebsites.net/";
})
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
Hope this helps someone else and thanks again to all who helped here
You need to capture your token and use https://jwt.ms to parse it.
According to your error message: invalid token The issuer is invalid, so you should check the iss Claims in the token to make sure it is as expected in the API The issuer matches. see here.
SOLUTION:
I found a solution thanks to all the help here. IS4 out of the box attempts to set the ISS / Issuer automatically. This works locally but in my production environment my container run in azure web apps for containers. Azure places my container inside of another container for load balancing/proxy to handle the https encryption as well. As a result there is a difference between the auto detected IS4 issuer in my container and the azure web app URL.
By manually setting the issuer in my code the error went away and everything works.
You can do this in two places
in your appsettings.jsson like:
"IdentityServer": {
"IssuerUri": "https://yourapp.azurewebsites.net",
or in code like this:
services.AddIdentityServer(options =>
{
options.IssuerUri = "https://your.azurewebsites.net/";
})
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
Hope this helps someone else and thanks again to all who helped here

Microsoft Graph 'created' subscription is not working with application token

I have a working application integrated with Microsoft Graph with application token received with a certificate.
I can subscribe to "updated,deleted" events on user contacts and calendars but I can't subscribe to "updated,deleted,created".
Resource used /users/<email>/contacts and /users/<email>/calendars
It gives me the following error on POST /subscriptions :
error": {
"code": "ExtensionError",
"message": "Operation: Create; Exception: [Status Code: NotFound; Reason: Not Found]",
"innerError": {
"request-id": "<skip>",
"date": "<skip>"
}
I just checked with a sandbox and it works with a user authenticated (I haven't check fully but at least it timeouts on a server side). Though with application token it's not working.
As per the documentation: 'User and group notifications support updated and deleted changeType.'
Reference:
https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/subscription
Drive root item notifications support only the updated changeType. User and group notifications support updated and deleted changeType.
I think I made something wrong in the beginning.
/users/<email>/calendars is a wrong link. To get user events it should be /users/<email>/calendar/events.
And /users/<email>/contacts created is working properly.

400 Bad Request in LUIS: Cannot find the specified subscription

I am creating a LUIS app using the LUIS programmatic API. After the app is successfully created and trained, I want to assign an API key to the app using this endpoint:
PUT /luis/api/v2.0/apps/{appId}/versions/{versionId}/assignedkey
Both my programmatic API key (obtained from luis.ai) and the normal API key (the one I am trying to assign, obtained from Azure Portal) are registered to the same email address.
However, when I am trying to send a request to the above endpoint, it fails with this error:
{
"error": {
"code": "BadArgument",
"message": "Cannot find the specified subscription"
}
}
I'm out of ideas for what I might be doing wrong, because exactly the same logic already worked before.
Is there some kind of way to "assign" an Azure subscription to my LUIS account?
Update:
I didn't find an answer to my question, but I found a workaround. Calling PUT /luis/api/v2.0/apps/{appId}/settings will set the application to "public", which means you can use any subscription key with it. See docs.
It seems that this endpoint is now deprecated because I get the following:
{
"error": {
"code": "DeprecatedException",
"message": "To assign a subscription key to an app, please go to the LUIS website at https://www.luis.ai and assign it from the app publish page."
}
}
In the luis page I see this:
The endpoint PUT /luis/api/v2.0/apps/{appId}/versions/{versionId}/assignedkey and /luis/api/v2.0/subscriptions are indeed deprecated. I contacted to LUIS support and they answered:
We are shifting the key management experience to happen only through the portal. Users no longer need to copy and paste keys, we offer a well-integrated experience that lists all the Azure keys inside our portal, key management details here.

What does Test Connection do in Azure AD Enterprise application?

I am in the process of configuring an Scim API with Azure AD. What does this "Test Connection" do when configuring an Enterprise Application?
In my case my API endpoint I want to configure is "https://myapi.company.com/api/v2" where resource URL's are in the form of "https://myapi.company.com/api/v2/scim/[Resource]". I don't include 'scim' in the Tenant URL (as per the image attached) as Azure AD adds that by default when sending requests (which is bit weird in a way). [AzureAD adds /scim/[Resource] e.g. /scim/Users to the base URL provided.] [Reference]1.
When I try (click 'Test Connection' or try to Save without testing connection) 'https://myapi.company.com/api/v2' for tenant URL Test Connection fails.
Error message 'You appear to have entered invalid credentials. Please confirm you are using the correct information for an administrative account.'. Which does not make any sense to me.
As experiments,
When try 'https://myapi.company.com/api/v2/scim/' it is successful.
When try 'https://myapi.company.com/api/v2' it is successful.
All 3 URLs above gives 404 when tried from Postman or from browser.
Can't understand what AzureAD do with Test Connection.
The test connection sends a request such as this:
GET /Users?filter=userName eq "non-existent user"
and expects a response such as this:
HTTP/1.1 200 OK
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 0,
"Resources": [],
"startIndex": 1,
"itemsPerPage": 20
}
https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/use-scim-to-provision-users-and-groups#get-user-by-query---zero-results
When you press Test Connection a couple of request will be sent to the Tenant URL(SCIM endpoint):
GET /scim/v2/Groups?excludedAttributes=members&filter=displayName+eq+%22AzureAD_Test-d3951745-df3d-40ae-a0a4-cc3099c34c47%22
GET /scim/v2/Users?filter=userName+eq+%22AzureAD_Test-d3951745-df3d-40ae-a0a4-cc3099c34c47%22
the actual displayName and userName requested are randomly generated, so an empty ListResponse is expected (with status code 200 OK):
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 0,
"Resources": [],
"startIndex": 1,
"itemsPerPage": 20
}
This behaviour is mentioned in the docs :
Microsoft Azure AD makes requests to fetch a random user and group to
ensure that the endpoint and the credentials are valid. It's also done
as a part of Test Connection flow in the Azure portal.

Google calendar push notification : Unauthorized webhook call

Currently we are in the process of developing one iPhone application that deals with google calendar. There was need of syncing calendar events to the server side. Everything works fine.
But for push notification , we are following this process
Whenever we post request to :
https://www.googleapis.com/calendar/v3/calendars/email#gmail.com/events/watch
with parameters
"id":Unique string ( channel id) ,
"type": "web_hook",
"address": "https://abc-api.herokuapp.com/user/notifications"
In the header , we are sending
Authorization : **Bearer 'Access_token'**
and content type : json
We already added domain as authorized domain in the google api console
Access_token is user's account access token .
We are getting "Unauthorized webhook call" error.
{
"error": {
"errors": [
{
"domain": "global",
"reason": "push.webhookUrlUnauthorized",
"message": "Unauthorized WebHook callback channel: https://abc-api.herokuapp.com/user/notifications"
}
],
"code": 401,
"message": "Unauthorized WebHook callback channel: https://abc-api.herokuapp.com/user/notifications"
}
}
Anyone here who can help us to solve the issue ?
You might want to check this post, providing solution like verifying if your domain have a valid (not self-signed) SSL license. Also in google-api-php-client GitHub, instead of setting https://example.com/google/push (resulted in Unauthorized WebHook callback channel) or https://www.example.com/google/push (allowed me to successfully open channel, and object has been returned, however webhook has not been fired) as address they tried https://www.example.com/google/push/index.php and worked.
One potential issue is if you're testing in Google's "try it" section of the documentation. It's not stated, but this particular request does not work there.
Otherwise, there are a few things that need to happen with the domain you are supplying in the address. First, you need to make sure its verified in the google developers console for the application you are hitting the api with. Additionally, you need to add the website property to your search console (even if its just an api) and verify ownership.
Also, once you get past the unauthorized address issue, you will get another error requiring a resourceId be supplied.

Resources