WSO2 API Manager not directing to Sandbox based on Sandbox Key - api

We have a deployed API which is responding correctly; however it has a different URL endpoint configured for Sandbox vs Production.
When I curl a request to the API Manager it is always the Production endpoint which is hit despite which Bearer token I submit. Authentication is working as if I submit an invalid Bearer token I get unauthenticated errors.
Any clues of where the mis-configuration might be?
(version 1.4.0)

When looking at your mentioned issue,I think you have used the 'PRODUCTION' scoped access token to invoke your SANDBOX endpoint.
After you defined two different endpoints as sandbox URL and production URL when creating the API,to invoke them you need to use different access tokens based on its scope [PRODUCTION/SANDBOX].
To invoke SANDBOX endpoint from your API,you need to use SANDBOX access token.
To find these production and sandbox endpoints related keys,you can navigate to APIStore->My Subscriptions page and view the keys under sections of 'production' and 'sandbox' in the particular subscription.And under each 'PRODUCTION/SANDBOX' keys section of subscriptions page,you'll see a separate access token and consumer key/secret.
Try invoking your SANDBOX endpoint of API,with above shown sandbox access token in 'My Subscriptions' page of APIStore or else you can use sandbox based consumer key/secret to generate sandbox scoped user tokens[1] and use those tokens to invoke your API sandbox based endpoint.
A sample cURL request to generate sandbox scoped user token would be as below;
curl -k -d "grant_type=password&username=xxx&password=xxx&scope=SANDBOX" -H "Authorization :Basic base64encoded_SANDBOX_based_consumer key:secret, Content-Type: application/x-www-form-urlencoded" https://ip:8243/token
[1] http://docs.wso2.org/wiki/display/AM140/Token+APIs#TokenAPIs-GeneratingusertokensGenerating

Related

Keycloak: Authorization between services and the public frontend

I have an application which consists of a frontend and several backend services. The authentication is done via Keycloak.
The workflow looks like this:
The user logs into the frontend and gets a token from Keycloak. This token is sent to the backend with every request.
The following image explains the current architecture:
In Keycloak I have the following clients:
1. Frontend
Access Type: public
Client Protocol: openid-connect
2. Core Service
Access Type: bearer-only
Client Protocol: openid-connect
3. User Service
Access Type: bearer-only
Client Protocol: openid-connect
How can I validate calls between services now?
I would imagine something like a service account and these have the possibility to call each other independently from the bearer-token from the frontend. The problem is that both services can be called from the frontend as well as between each other.
Edit:
My API is written with NestJS.
The API of the user-service:
And this is how I call the user-service in my core-service:
and this is my keycloak configuration for the the user-service:
At the moment I don't add anything to the request and I don't have any extra configuration on the interface. So I added the #Resource('user-service')-Annotation to the Controller and the #Scope()-Annotation to the Endpoint.
After that I don't get an error immediately and the endpoint is called.I can log that the logic is executed. But as response I still get a 401 Unauthorized Error.
Do I need to specify a scope or what do I need to add in the #Resource-Annotation?
Edit 2:
I'll try to show you my current situation with many screenshots.
Initial situation
Here is your drawing again. For me, points 1-5 work and point 8 works even if I do not call another service.
My Configuration
That this works, I have the following configuration:
Just Frontend and Core Service
Frontend:
Core-Service:
For the core service (gutachten-backend), I do not need to make any further configurations for this. I also have 2 different roles and I can specify them within the API.
Using Postman I send a request to the API and get the token from http://KEYCLOAK-SERVER_URL/auth/realms/REALM_NAME/protocol/openid-connect/token.
These are my 2 testing methods. I call the first one and it works. The following is logged. Means the token is validated received and I get Access:
Calling the user service
Now I call the second method. This method calls the user-service.
This is my request in the core-service:
I do not add anything else to my request. Like a bearer token in the header.
The endpoint in the user service is just a test method which logs a message.
This is my configuration for the user service:
I have now tried something with resources, policies and permissions.
Resource
Policies
Role-Policy
Client-Policy:
Permission
And analogously the client permission
Questions and thoughts
All steps from the first drawing seem to work except 6 and 7
Do I need to add more information to my request from core service to user service?
How to deal with root url and resource urls?
In the code in the API, do I need to additionally configure the endpoints and specify the specific resources and policies? (NestJS offers the possibility to provide controllers with a #Resource('<name>') and endpoints with #Scopes([<list>]))
Additionally, through a tutorial on setting up keyacloak in NestJS, I turned on the following config:
This adds a global level resource guard, which is permissive.
Only controllers annotated with #Resource and
methods with #Scopes are handled by this guard.
Keycloak's Token Verification API can do it.
This is one of Architecture for Authorization of resource access permission.
Between Core Service and User Service, Core Service needs to verify the access-token to Keycloak.
It means this token can access the User service API Yes(Allow) or No(Deny)
This is API format
curl -X POST \
http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
-H "Authorization: Bearer ${access_token}" \
--data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
--data "audience={resource_server_client_id}" \
--data "permission=Resource A#Scope A" \
--data "permission=Resource B#Scope B"
Demo Keycloak Token URL: localhost:8180
Authorization Enabled Realm: test
Authorization Enabled Client: core-service
Client Resource: resource:user-service
User1 : can access it (ALLOW) password: 1234
User2 : can access it (ALLOW) password:1234
Steps
Get User Access Token(instead of login) ->
Preparations
ready to assign access-token(named user-token) variable in Postman
var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable("user-token", jsonData.access_token);
Get Token URL from Keycloak UI, click the Endpoints
Get User1's access token
with Bearer Token option with {{user-token}} in Authorization Tab
Verify with user1 token from Core Service to Keycloak
return 200 OK from Keycloak (ALLOW) - it is Circle 4 and 5 in my Architecture.
So Core Service forward API call to User Service for accessing service
Note - needs to finish Keycloak Permission setting
Verify with user2 token from Core Service to Keycloak
return 200 OK from Keycloak (Allow) too.
So Core Service return an error to Front-end, like this user can't access a resource of User Service.
More detail information is in here
Keycloak Permission setting
Create Client
Create Client Resource
Add Client Role
Add Client Policy
Add Permission
All user mapping into Client role
This is Configuration in Keycloak
Create Client
Create Client Resource
Add Client Role
Add Client Policy - role based
Add Permission
All user mapping into Client role - any user if you want to add to access the resource.
For people who have the same problem in the future. The answer from #BenchVue helped a lot to understand the concept in general.
What was missing is that a token must also be added for each request between services. Namely the token of the client.
So before the request is sent, the following query takes place. This is the method to get the token for a client:
getAccessToken(): Observable<string> {
const header = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
return this.httpService.post(
'{{keycloakurl}}/auth/realms/{{realm}}/protocol/openid-connect/token',
`grant_type=client_credentials&client_id={{clientId}}&client_secret={{clientSecret}}`,
header).pipe(
map((response) => {
return response.data.access_token as string;
}
));
}

Having problem Authorizing Authenticated user account in Web API

I'm using ASP.Net Core 6 to build a secured Web API.
HOW I BUILT IT
dotnet new webapi --auth SingleOrg --aad-instance https://login.microsoftonline.com/ --client-id <CLIENT ID> --domain company.onmicrosoft.com --tenant-id <TENANT ID> --calls-graph true -o GraphTestService
APP REGISTRATION OF WEB API
I added a Scope in the Export API "EmployeeRecord.Read"
APP REGISTRATION FOR CLIENT (Public Client)
Added permission for Graph API (User.Read)
Added permission "EmployeeRecord.Read"
HOW I GET TOKEN USING THE CLIENT
I'm using "InteractiveBrowserCredential".
Everything works fine up until the Web service tries to call Graph API. It throws MsalUIRequiredException.
Understandable, since I did not include any graph API permissions when I requested a token.
FINALLY, THE PROBLEM
When I inspect the Bearer token that's returned, it has the "EmployeeRecord.Read" scope. Ok, that's fine. The Web API authorizes it; but the token doesn't have any permissions for Graph API.
When I add a graph API permission to the scopes, I get
AADSTS28000: Provided value for the input parameter scope is not valid because it contains more than one resource. Scope api://<APP URI ID>/EmployeeRecord.Read https://graph.microsoft.com/User.Read offline_access openid profile is not valid.
If I only include the graph API permission, the Web API returns an Unauthorized error.
WHAT I'VE TRIED
In addition to playing with the scopes, I tried adding my client application to the Web API app registration under the "Expose an API / Add A client Application". This made no difference. No difference in token or errors.
You are trying to add scopes for 2 different resource ,the scope parameter cannot be used to specify permissions for multiple resources similar issue .
we recommend you to use MSAL libarry , MSAL will store tokens for you and refresh whenever token is expired. Just call acquireTokenSilent to get an access token silently, and if you get an error, call acquireToken (see details on error handling here: https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-handling-exceptions#msal-for-ios-and-macos-errors)
for more info please check similar issue
Thanks

Always get "redirect_uri_mismatch" under google oauth progress

I am developing a website which need google-login button. But i failed in getting the access_token.
Here is my configuration page and curl result.
why curl doesn't work.
The problem you are having is that you have created web browser credentials and you appear to be testing with curl. Curl by itself would be run in a command prompt or shell script there for it would be installed credentials not web browser credentials.
Go to google developer console and create desktop app type creetinals Then you can follow the calls below in order to authorize to Google and get an access token and a refresh token.
Notice how desktop apps use urn:ietf:wg:oauth:2.0:oob for a redirect uri this means just send it back where it came from.
# Client id from Google Developer console
# Client Secret from Google Developer console
# Scope this is a space separated list of the scopes of access you are requesting.
# Authorization link. Place this in a browser and copy the code that is returned after you accept the scopes.
https://accounts.google.com/o/oauth2/auth?client_id=[Application Client Id]&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=[Scopes]&response_type=code
# Exchange Authorization code for an access token and a refresh token.
curl \
--request POST \
--data "code=[Authentcation code from authorization link]&client_id=[Application Client Id]&client_secret=[Application Client Secret]&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code" \
https://accounts.google.com/o/oauth2/token
# Exchange a refresh token for a new access token.
curl \
--request POST \
--data 'client_id=[Application Client Id]&client_secret=[Application Client Secret]&refresh_token=[Refresh token granted by second step]&grant_type=refresh_token' \
https://accounts.google.com/o/oauth2/token
code ripped from GoogleAuthenticationCurl.sh
YOu may also be interested in Which type of credentials should you create? which explains how to decide which type of Google credentials you need to use for the application you are developing.
your web application.
Redirect uri mismatch with a true web application is most often a configuration issue. If you are using a servicer sided programming language you simply need to take the redirect uri that the error message is telling you is wrong and place that in Google Developer console for your web application as a Redirect uri. Google OAuth2: How the fix redirect_uri_mismatch error. Part 2
If on the other hand you have a Client sided web application using javascript it will state that the issue is with the JavaScript origin. It is still a configuration issue. However this time you need to take the URL it is telling you is wrong and place that in the javascript origin field in Google developer console Simple solution for redirect_uri_mismatch error with JavaScript
YOu do not need both Redirect URI and Javascript origin its one or the other.
Fixed it.
The problem is that i have added two version of redirect uri in the google console:
http and https
In the first step, i redirect customer to the oauth page "https://accounts.google.com/o/oauth2/v2/auth" with http version redirect uri.
In the second step i try to got the access token with https version redirect uri, so i got this error.

Format a HTTPS call to Google Cloud using simple API key

I am trying to connect to Google Cloud from an embedded device so I have no access to OAuth authentication. The documents show that I can use simple API key for connecting. I have created a simple API key but I am having problems using it.
I can test the API functions successfully on https://developers.google.com/apis-explorer/?hl=en_US#p/pubsub/v1/ but on this developer's site I don't enter my API key (maybe one is generated automatically in the background).
When I try the same command using curl I get a 401 error:
"Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.", "status": "UNAUTHENTICATED"
But I am copying the GET or POST command directly from the online API tester and adding my key at the end:
curl -X POST -d '{"policy":{"bindings":[{"role":"roles/editor","members":["serviceAccount:charge...."]}]}}' https://pubsub.googleapis.com/v1/projects/pl..../subscriptions/arriveHomeSub:setIamPolicy?key=AIz....
What am I missing?
With the limited information you have provided, it is tough to identify the root cause but these are some of the possible ones:
You have not used quotes for the URL argument to curl. This could lead to some characters which are part of the URL to be interpreted by your shell in a different manner. Characters like & are usual culprits although they don't seem to be part of the URL you pasted.
curl -X POST -d '{"policy":{"bindings":[{"role":"roles/editor","members":["serviceAccount:charge...."]}]}}' 'https://pubsub.googleapis.com/v1/projects/pl..../subscriptions/arriveHomeSub:setIamPolicy?key=AIz'
You have not described how you're generating your API key and hence I feel that could be one of the possible issues.
You can go over the steps for using Google OAuth 2.0 from Google, it covers a lot about client secrets, access tokens and refresh tokens.
As long as you have your client ID and secret, you can call Google OAuth APIs to generate an access token.
You pass in the current access token as the key argument to your REST API.
Access tokens have very limited lifetime and might need refreshing periodically. If your application needs to periodically refresh access tokens, consider storing the refresh token in your application in a secure manner.

Getting error 502 when using REST API to retrieves list of all applications

GET /imfpush/v1/apps HTTP/1.1
Host: mobilefoundation-3b-mf-server.mybluemix.net
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImp....
Content-Type: application/json
another type of invocation
curl -X GET -H "Authorization: Bearer eyJhbGciOiJSUzI1N...." "https://mobilefoundation-3b-mf-server.mybluemix.net/imfpush/v1/apps"
Error 502: Failed to make token request, reason: Unsuccessful request to Authorization Server, server responded with status code: 400 and body : {"errorCode":"invalid_client"}, check the Authorization URL: http://localhost:8080/mfp/api/az/v1/token
TL;DR: right now looks like there is a bug in the /imfpush/v1/apps endpoint where it does not filter the applications by the vendor (APNS, GCM, WNS), so you can only get a list of all applications instead...
Note however that it all depends on your end goal. You can accomplish this by code or by using tools such as curl or Postman, Swagger etc... it all depends on what you want to achieve.
Here are 3 ways:
In the local development server - not available in Mobile Foundation service on Bluemix, you can use this URL to see the REST endpoints exposed in Swagger. You can then view push-enabled applications with this one: http://localhost:9080/doc/?url=/imfpush/v1/swagger.json#!/Applications/getAllApplications
First, in MobileFirst Operations Console > Runtime Settings > Confidential clients:
Add (just an example, choose your own) a new user client (id: user, secret: user)
Add the apps.read and push.application.* scopes
Be sure to click on the knob and add the apps.read and push.applications.* scopes.
You will also be asked to authorize. Use the username and password for the user confidential client that you previously created.
Using the /imfpush service, as described below.
Using the mfpadmin service, as described below.
In my examples I will use Postman.
In MobileFirst Operations Console > Runtime Settings > Confidential clients:
Added (just an example, choose your own) a new user client (id: user, secret: user)
Added the apps.read and push.application.* scopes
Obtained an access token by making a POST request to http://localhost:9080/mfp/api/az/v1/token with:
Authorization tab:
Type: Basic Auth
user: user
password: user
Body tab:
x-www—form-urlencoded
grant_code: client_credentials
scope: apps.read push.application.*
Obtained the list of applications by making a GET request to http://localhost:9080/imfpush/v1/apps with:
Headers tab:
Authorization: Bearer the-access-token-from-step-2
To filter the list by platform, the URL should change to the following, like the example in the API documentation: http://localhost:9080/imfpush/v1/apps/?expand=true&filter=platform==A&offset=0&size=10 But since this does not work right now... use: http://localhost:9080/imfpush/v1/apps/
Of course, you need to change localhost to your server's host.
To only obtain a list of all applications, it'd be faster to use the mfpadmin service applications endpoint. Using Postman:
Created a new GET request to http://localhost:9080/mfpadmin/management-apis/2.0/runtimes/mfp/applications
You can change the domain to yours.
In the Authorization tab, I have set the following:
Type: Basic Auth
Username and Password: your username and password (to the console)
In return I have received a list of registered applications.