Is it possible to define extra details in the callerContext of a Cognito pre-token lambda call? - amazon-cognito

In Cognito, I have a pretoken generation hook setup and my lambda receives this
{
"callerContext": {
"clientId": "abcde12345" // some hash,
...
},
"request": {
"userAttributes": {
"email": "foo#bar.com",
"sub": "someUserID",
...
},
...
},
...
}
I would like to be able to determine what claims to assign this user, not by the user attributes, but by the app the user is using to login.
Naturally, I could just use callContext.clientId but that can change when an app client is recreated. Is there a way to use a custom string from the callerContext? e.g
"callerContext": {
"clientId": "abcde12345" // some hash,
"appName": "FoobarGame"
}
Is it possible to define this custom string in the Cognito App client instead of relying on the cognito Id?(which can change upon recreation).

I don't think this is doable. At least in the document, they haven't mentioned a way to use a custom string within the callerContext.
As your requirement is: to avoid the code changes, based on the changes in client id, I would suggest to use lambda environment variables.
So we can specify the client Id as an environment variable. Then in the code, retrieve it from there. With that approach, way we don't have to change the code and only the environment variable value.
Would that work for you?

Related

Passing State and Other Attributes at Login Using Microsoft.Identity.Web

I'm having troubles getting the .NET Core 6.0 authentication libraries working as I did with prior versions of .NET Framework. Specifically, I'm using Microsoft.Identity.Web, but have not figured out how to get the scope and state parameters passed in and out that I want. The signin-oidc keeps overriding these values with the ones I am trying to manage dynamically. If I use the old method, which is just a RedirectResult to a properly formed URL for authentication, signin-oidc overrides the values I send in on the query string. If I use the Challenge class with a list of name value pairs in the Properties collection (like state, consent, scope, etc), signin-oidc still overrides them.
I would like to have something as simple, readable, and operationally efficient as when I could just redirect to a URL with all the query string parameters, and provide a callback URL that had a "code", "error", "state", and other parameters in the method. Right now I'm tied in knots over getting the right values over, and trying to get them back in a generic event override in the app's Program start up code. Some stuff shows up in a generic Properties bag, but not in the logical "State" property of the context argument's ProtocolMessage. What am I missing?
These are for cases where the user has authenticated to the site, and now I am trying to get them to consent and get a token for another Azure AD app.
Here is an example of using a simple redirect:
https://login.windows.net/organizations/oauth2/v2.0/authorize?response_type=code%20id_token&client_id=aaaaaaaa-d4d2-4499-8e2a-b6957678fe80&redirect_uri=https%3A%2F%2Flocalhost%2Ffilemonweb%2Fhome%2FProcessCode&state=my%20state%20stuff&scope=openid%20offline_access%20api%3A%2F%2F1f43d4aa-d4d2-4499-8e2a-b6957678fe80%2F.default&response_mode=form_post&nonce=aee597a2-f050-48d0-9e3c-6c62f089b76c&prompt=consent
Here's an example using Challenge:
return Challenge(new AuthenticationProperties(
new Dictionary<string, string?>() { { "state", "my state stuff" } },
new Dictionary<string, object?>() {
{ "client_id", ServiceConfig.Configuration.FILEMON_WEB_CLIENT_ID },
{ "type", "code%20id_token" },
{ "scope", "openid%20offline_access%20" + Uri.EscapeDataString(ServiceConfig.Configuration.FILEMON_WEB_SCOPE) },
{ "response_mode", "form_post" },
{ "nonce", Guid.NewGuid().ToString() },
{ "prompt", "consent"} })
{ RedirectUri = "filemonweb/home/tests" },
"OpenIdConnect");
With the Edge dev tools network sniffer, I see that the request arrives as expected with the top example (properly formatted URL). When the response is returned, I see it go to the redirect URI I requested, but the app sends a 302 response, and the response header includes a Location value that changes the redirect URI from the one I requested, to signin-oidc. For example, like this:
https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?client_id=1f43d4aa-d4d2-4499-8e2a-b6957678fe80&redirect_uri=https://localhost/filemonweb/signin-oidc&response_type=code&scope=openid profile offline_access user.read&code_challenge=ZXiKTCHjJJZwo54YdulG7h45_9e4EOBnSv_kxNOTv2w&code_challenge_method=S256&response_mode=form_post&nonce=637860882099818382.MDA0NGY1MGYtZWI0Ny00ZDU3LWJiMjQtZmE1ODk5ODdkYTEyYjQ0M2EzNjgtNzJjZi00ZjEyLWIxNTgtMGE2Y2JkYzc5YWE1&client_info=1&x-client-brkrver=IDWeb.1.16.0.0&state=CfDJ8MyJsY2aFrtOs5mEt79T88KiVV7RXqWFSO0rcSzX-NZcXlZ52qcIxpYLyz0wuWkqCh5vYPEg5Wj-YRUNMD542mvxJDGiKHz62k1hTctyvJxEtlIcZtbvLu1VOE9lNJdd6dKttBP2oi5nwDVZZC96-4bohWxxzfSk0-co8iet8xWhv8k0V2Iva1eatQ__LHOJofFQSV2IUHHmzokTB3s6reO4iLcGCyANYQWl9tp24IdQMWrwp3ZE4-DCDDQ1xzG5DZSbLAAyN29gOe5aAUwJBhmNIYX4Lm7fdsS9Bq9Xsh65h4E8Pff3U531KlDdY2WZK3gB-fyoML6rpT7DRQBN1Z5ls686pyMxtQRVN-LcQEYXCsmv7WZF3yiSQ-ctIN3X1GOehgTPJrSxpb8LxoT-Z9Bo_lQLEmwOvXw-9qbDzntv&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=6.12.1.0
When it sends that 302 response, it changes the State parameter, the Scope parameter, etc.
Thanks.

OData: Change URL value for entity type in EDM Model

I'm working with a ASP.NET Core Web Api project that uses OData for the exposed endpoints and are consumed with a Simple.OData.Client.
Some of my endpoints are:
http://{baseUrl}/odata/Vehicle --> this works perfectly
But I'm having issues with these two:
http://{baseUrl}/odata/Vehicle/Brand
http://{baseUrl}/odata/Vehicle/Type
Basicly, I can't modify my EDM Models for modifying the URL property that is exposed in the metadata of OData. My EDM looks like this:
private IEdmModel GetEdmModel()
{
var odataBuilder = new ODataConventionModelBuilder();
odataBuilder.EntitySet<Vehicle>("Vehicle");
odataBuilder.EntitySet<VehicleType>("VehicleType");
odataBuilder.EntitySet<VehicleBrand>("VehicleBrand");
return odataBuilder.GetEdmModel();
}
And the metadata that I get when I navigate through http://{baseUrl}/odata/ is the following:
{
"#odata.context": "https://localhost:44332/odata/$metadata",
"value": [
{
"name": "Vehicle",
"kind": "EntitySet",
"url": "Vehicle"
},
{
"name": "VehicleType",
"kind": "EntitySet",
"url": "VehicleType"
},
{
"name": "VehicleBrand",
"kind": "EntitySet",
"url": "VehicleBrand"
}
]
}
I couldn't find a way to maintain the name as it is, but modify the "url" property shown on the JSON to point to my proper endpoint. I want this result:
{
"name": "VehicleBrand",
"kind": "EntitySet",
"url": "Vehicle/Brand"
}
Any of the methods exposed on EntitySetConfiguration or ODataConventionModelBuilder seems to have a way to specify a different URI for a registered entity type.
Someone has faced this issue? I'm sure that might be some way of solving this.
Odata Route or Navigation Property?
Please have a look at that documentation here
Long story short - an OData URI consists of:
The service root
The OData path
Query options
For example. This is a Path that goes to the EntitySet "Products", takes the first, and then Navigates (see Navigation Properties) to its Supplier.
https://example.com/odata/Products(1)/Supplier?$top=2
------------base---------|-----Path-----------?---options---
So, everything you make accessible at root level should have its own path, and the / telling Odata to navigate onward from there.
So, now for OData, it would freak the hell out of most clients and surely be bad style if you would define an entitysets path as something that can be confused with another entititysets navigation property.
But if you REALLY need to do it, maybe you can achieve it by defining a custom routing convention.
But dont! It will only make trouble
Do you want a navigation property?
If you want the set that "Type" returns to be dependent on the Vehicle, you should define a navigation property on Vehicle instead.
Greetings, Mike

Custom API route will respond with Forbidden if JWT token generated with Skoruba (Identity Server 4) is used

We've started implementing a new Web API with ASP.NET Core 2.2 and it has been decided that it should use Identity Server 4 for authentication/authorization duties. Furthermore, its Skoruba implementation has been chosen as it looks like it should fulfill most, if not all our needs in that regard.
We got the identity server and Skoruba up and running, but when it comes to consuming the JWT token in our own API, even assigning just one role to the test user, we'll keep hitting the same brick wall. The following request to the Skoruba API will respond with a 200:
http://localhost:5000/connect/token:
It successfully returns a JSON string with access_token, expires_in and token_type ("Bearer").
After that, a request to the http://localhost:5000/connect/userinfo route of the API with the following header
will also respond with a 200 and return the following JSON string:
{
"sub": "aeccf460-7d0d-41ae-8b52-a051138f5c05",
"role": "Administrator",
"preferred_username": "dev",
"name": "dev"
}
Please take notice that "role": "Administrator" assigned to user dev is something I set up myself using the Skoruba Admin UI, so that JSON is pretty much what I wanted. So for all intended purposes it looks like I have the information I need right now. I just can't consume it. If I try to retrieve the JWT token in our own back end, I am successful (this is obviously just for testing purposes):
[HttpGet("GetAccessToken")]
[AllowAnonymous]
public string GetAccessToken()
{
var accessToken = HttpContext.Request.Headers["Authorization"];
var token = accessToken.First().Remove(0, "Bearer ".Length);
return token;
}
With all that said, onto the actual problem: calls to a route that demands authorization in our API are treated in the same fashion as calls to Skoruba's userinfo action (particularly, the headers):
Inside this same Controller ("Foo"), I implemented a simple Get method, which should only be accessed with the correct role, which I assume is information fetched from HttpContext.Request.Headers["Authorization"] and hoped the framework would use it accordingly:
[HttpGet]
[Authorize(Roles = "Administrator")]
public IActionResult Get()
{
try
{
var response = ConvertListToJsonResponse(GetAll()); //Don't mind me
return Ok(response);
}
//...
}
At this point, my API server responds with the infamous 403 Forbidden status code. Not sure where to go from here and research proved unwieldy so far. Any help is appreciated, I'll provide more code and info if necessary.
EDIT
This is the generated token:
eyJhbGciOiJSUzI1NiIsImtpZCI6IjA4NTMzNmFmZTY0Yzg2ZWQ3NDU5YzE5YzQ4ZjQzNzI3IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1Njg3NDU5NTgsImV4cCI6MTU2ODc0OTU1OCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwL3Jlc291cmNlcyIsImNsaWVudF9pZCI6ImF1dGhfdGVzdCIsImNsaWVudF9hY2Nlc3NfcmlnaHRzIjpbImxpc3QiLCJhcHByb3ZlIiwia2VlcCJdLCJzdWIiOiJhZWNjZjQ2MC03ZDBkLTQxYWUtOGI1Mi1hMDUxMTM4ZjVjMDUiLCJhdXRoX3RpbWUiOjE1Njg3NDU5NTgsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsInJvbGVzIl0sImFtciI6WyJwd2QiXX0.Ihsi6W5ukGcZ4Chkuk5XMaoqTkUR_1hBQlIcdHtMWiBA-EyAIncX5STCng_6ZPgN89Np6Y_hemFFyVtHEdN_vP6i0HuaXgznzrnJ4zq4Iiz9jxpZqpSSE9cXpSG8hPOZe5kGfD2J6_GPxnraGH_1ZF94AhmlspIvqFAAQrQ-0c7-dCduP4ledkQvBKz-rXszGp35W7Gb5nvpcVt4oe67mqETdwtgGengk2eCwHeKdA94EYnj_HErPNTjJhh5k75fDQ0IiOS-xHRK8BQmLhRh_UZwB3H5qZymFJNr_yb-ljFqIeEHptSWLBO1XrKYs1BqB9KwxIROKqmxeNGTnpCUSQ
The resulting payload:
{
"nbf": 1568745958,
"exp": 1568749558,
"iss": "http://localhost:5000",
"aud": "http://localhost:5000/resources",
"client_id": "auth_test",
"client_access_rights": [
"list",
"approve",
"keep"
],
"sub": "aeccf460-7d0d-41ae-8b52-a051138f5c05",
"auth_time": 1568745958,
"idp": "local",
"scope": [
"openid",
"profile",
"roles"
],
"amr": [
"pwd"
]
}
I see the claims I added to the client, but what I really need at the moment is simple Authentication, which I suppose should be provided by a role. Or am I completely off?
This question, and more specifically, this answer helped me to understand what was going on and map Skoruba's UI functionalities to IdentityServer4 inner workings. Credits goes to Ruard van Elburg.

Spring security WSO2 IS integration - Figure out how to assign authorities/customize wso2 token

I am very stuck with this issue for a couple of days.
So what I am trying to do is to assign ROLES with spring security framework. My goal is to decode token that I get from WSO2 Identity Server 5.0 through openid and assign the Role so I can authorize the request based on Roles (AUTHORITIES)
This is my SecurityConfig class in simple spring boot app
#Profile("oauth")
#Configuration
#EnableResourceServer
public class SecurityConfig {
}
So, with this configuration, I am able to decode the token.
However, in debug mode, when I made a request with the id_token to the simple spring boot app, I received an error:
java.lang.ClassCastException
java.lang.String cannot be cast to java.util.Collection
And it happens in DefaultAccessTokenConverter class, particularly in the line of code when the map object is converted to String [] roles
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
...
if (user==null && map.containsKey(AUTHORITIES)) {
#SuppressWarnings("unchecked")
String[] roles = ((Collection<String>)map.get(AUTHORITIES)).toArray(new String[0]);
authorities = AuthorityUtils.createAuthorityList(roles);
}
OAuth2Request request = new OAuth2Request(parameters, clientId, authorities, true, scope, resourceIds, null, null,
null);
return new OAuth2Authentication(request, user);
}
This is my WSO2 decoded token
{
"auth_time": 1464819792,
"exp": 1464823490,
"azp": "U1PXsuyV_tdBERmZIoHHnqoGkWIa",
"authorities": "[\"ROLE_ADMIN\",\"approver\",\"Internal\/everyone\"]",
"at_hash": "Hh2LUZl3Bp6yDqyZt4r6Gg",
"aud": [
"U1PXsuyV_tdBERmZIoHHnqoGkWIa"
],
"iss": "https://localhost:9443/oauth2/token",
"locality": "[\"ROLE_ADMIN\"]",
"iat": 1464819890
}
It seems that Spring expects Array of String, not String object (there is a double quote at the beginning and the end of value in authorities.
The aud format seems to be what the spring expects.
So, there are two options I can think o
1. Write some configuration in Spring Oauth2 (I have not figured this out yet)
2. Configure WSO2 Identity Server (This what I've been trying to do).
There are some resources saying that we can implement our own JWTTokenGenerator in WSO2 carbon. From looking at the code, it seems this is where the double quotes are generated in the claim.
org.wso2.carbon.identity.oauth2.authcontext.JWTTokenGenerator
I hope there is someone else who has been going through this.
Thank you very much.
Please find the default implementation here [1]. Also it is better if you can go with IS 5.1.0 for 5.1.0 refer [2]. After building custom JWTTokenGenerator copy it to repository/components/lib. Change
<TokenGeneratorImplClass>
element in identity.xml according to your custom implementation.
[1] https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/components/identity/org.wso2.carbon.identity.oauth/4.2.3/src/main/java/org/wso2/carbon/identity/oauth2/authcontext/JWTTokenGenerator
[2]https://github.com/wso2/carbon-identity/tree/master/components/oauth/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authcontext
Thank you! That could work too! but for easier implementation, we use 5.2.0 beta version that that produce array of string. T

How can I reauthenticate with Facebook after the OAuth 2.0 changes to the sdk?

In our app we had some actions that we required the user to reauthenticate before proceeding. We used code like below to make this happen.
FB.login(
function(response) { /* code here */ },
{auth_type: 'reauthenticate', auth_nonce: '...'}
);
It looks like the auth_type option is no longer supported, because I am getting the following log message: 'FB.login() called when user is already connected.' and the user is not being asked to reauthenticate.
Does anyone have any ideas how to reauthenticate after the changes for OAuth 2.0?
It appears that, for the time being (and I qualify that because Facebook seems to change their API response on a whim), you can get auth_type: reauthenticate to work properly IF you also specify permissions (the scope parameter in OAuth 2.0). Check out this example:
http://www.fbrell.com/saved/a78ba61535bbec6bc7a3136a7ae7dea1
In the example, click Run Code, and then try the "FB.login()" and "FB.login() with Permissions" buttons. Both are coded to use auth_type: reauthenticate, but only the latter actually gives you the FB prompt once you are logged in.
Here are the relevant examples:
// DOES NOT PROMPT
document.getElementById('fb-login').onclick = function() {
FB.login(
function(response) {
Log.info('FB.login callback', response);
},
{ auth_type: 'reauthenticate' }
);
};
// PROMPTS AS EXPECTED
document.getElementById('fb-permissions').onclick = function() {
FB.login(
function(response) {
Log.info('FB.login with permissions callback', response);
},
{ scope: 'offline_access', auth_type: 'reauthenticate' }
);
};
So, the answer is, Yes, auth_type: reauthenticate DOES work, but ONLY if you also specify a valid scope parameter. (And yes, I tried it with an empty scope, and it acted the same as not using scope at all.)
You can use an iframe to make sure the cookie is always valid.
facebook auto re-login from cookie php
Using FacebookRedirectLoginHelper::getReAuthenticationUrl everything works fine.
Internally the method put 'auth_type' => 'reauthenticate' and pass also all the permissions required.
Now the issue is that only prompt to the user to re-enter the password without the possibility to "switch" between users or without the possibility to insert also the username.
Does someone found a solution for this issue?
I manage an application with multi accounts and when the user need to generate again the token this is an issue :(
Thanks, Alex.