Link AccessToken to a user in Loopback - access-token

I wanted to add a custom attribute (expireAt) to the access token for it to be used by MongoDB to automatically remove the expired access token when expired.
Adding the custom attribute while creating the access token using AccessToken model is working well:
const ttl = 600;
const expireAt = new Date();
expireAt.setSeconds(expireAt.getSeconds() + ttl);
const token = await AccessToken.create({ ttl, expireAt });
However, when I want to create an access token for a user, I can't add the custom attribute exprieAt when creating the token, so I have create first, and then update it:
const ttl = 600;
const expireAt = new Date();
expireAt.setSeconds(expireAt.getSeconds() + ttl);
// Create the access token for the user
const token = await user.createAccessToken(options);
// Update token to set the custom date and time to expire
token.expireAt = expireAt;
token.save();
// Return the token together with the user data
return Object.assign({}, token.toJSON(), { user });
Is there a way I can create the token for a user with the custom attribute (either using instance method or model method is fine), without doing two steps - create and update?

So it seems that AccessToken model has the relationship set up with the user via userId attribute (ref: https://github.com/strongloop/loopback/blob/master/common/models/access-token.json#L27).
{
"name": "AccessToken",
"properties": {
"id": {
"type": "string",
"id": true
},
"ttl": {
"type": "number",
"ttl": true,
"default": 1209600,
"description": "time to live in seconds (2 weeks by default)"
},
"scopes": {
"type": ["string"],
"description": "Array of scopes granted to this access token."
},
"created": {
"type": "Date",
"defaultFn": "now"
}
},
"relations": {
"user": {
"type": "belongsTo",
"model": "User",
"foreignKey": "userId"
}
},
"acls": [
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
}
]
}
To link the token to the user, we only need to pass in the value userId:
AccessToken.create({ ttl, expireAt, userId });

Related

Adaptivecards Send POST call to external API in MS Teams

I am building a script that pushes adaptive card messages to an MS Teams channel connector via a webhook requesting the approval of a supervisor.
I want to put two buttons on the bottom of the message, one to decline and another to approve the request. For this, I need to push a boolean value to an API endpoint. My initial idea was to create an API endpoint accepting a JSON body and looking into the JSON body for approval over a POST request but apparently, this is no longer supported in MS Teams and then I was thinking to use Action.OpenUrl to push this as a query parameter in the URL, but unfortunately this opens a new tab with the query parameter.
Is there any other way to achieve this? This is a sample JSON for the MS Teams webhook:
{
"type": "message",
"attachments": [
{
"contentType": "application/vnd.microsoft.card.adaptive",
"contentUrl": null,
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.5",
"msTeams": {
"width": "full"
},
"actions": [
{
"type": "Action.OpenUrl",
"title": "Approve",
"url": "https://<api_endpoint_url>?approved=true"
},
{
"type": "Action.OpenUrl",
"title": "Decline",
"url": "https://<api_endpoint_url>?approved=false"
}
]
}
}
]
}
This sample shows a feature where user can send task request to his manager and manager can approve/reject the request in group chat.You can try like below code:-
case "approved":
string[] approvedCard = { ".", "Cards", "ApprovedCard.json" };
var approvedAttachment = GetResponseAttachment(approvedCard, data, out cardJson);
Activity approvedActivity = new Activity();
approvedActivity.Type = "message";
approvedActivity.Id = turnContext.Activity.ReplyToId;
approvedActivity.Attachments = new List<Attachment> { approvedAttachment };
await turnContext.UpdateActivityAsync(approvedActivity);
response = JObject.Parse(cardJson);
adaptiveCardResponse = new AdaptiveCardInvokeResponse()
{
StatusCode = 200,
Type = "application/vnd.microsoft.card.adaptive",
Value = response
};
return CreateInvokeResponse(adaptiveCardResponse);
Ref Sample-https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-request-approval/csharp

Asp.Net BoilerPlate - PermissionManager.GetAllPermissions() not getting a new permission

I created a default solution from BoilerPlate's website with angular.
I need to create a new permission to assign to a user. So I added it in my authorization provider:
public class PilotoConciliacaoAuthorizationProvider : AuthorizationProvider
{
public override void SetPermissions(IPermissionDefinitionContext context)
{
context.CreatePermission(PermissionNames.Pages_Users, L("Users"));
context.CreatePermission(PermissionNames.Pages_Users_Activation, L("UsersActivation"));
context.CreatePermission(PermissionNames.Pages_Roles, L("Roles"));
context.CreatePermission(PermissionNames.Pages_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host);
context.CreatePermission(PermissionNames.Pages_CadastrarPdv, L("TituloCadastrarPdv"), multiTenancySides: MultiTenancySides.Host);
}
private static ILocalizableString L(string name)
{
return new LocalizableString(name, PilotoConciliacaoConsts.LocalizationSourceName);
}
}
In the case, it's PermissionNames.Pages_CadastrarPdv.
I've created the constant and the localizable resource.
But when I run the GetAllPermissions service, it only gets 3 of them:
"result": {
"items": [
{
"name": "Pages.Roles",
"displayName": "Funções",
"description": null,
"id": 0
},
{
"name": "Pages.Users.Activation",
"displayName": "Users activation",
"description": null,
"id": 0
},
{
"name": "Pages.Users",
"displayName": "Usuários",
"description": null,
"id": 0
}
]
},
"targetUrl": null,
"success": true,
"error": null,
"unAuthorizedRequest": false,
"__abp": true
What am I missing?
Thanks in advance.
What happening is that you've specified this permission just for host user, as I can see you are logged as a tenant so you won't see this permission neither tenant permission.
If you need MultiTenancy active and you need this permission to all users you have to remove this section of permission especification and put it like this:
context.CreatePermission(PermissionNames.Pages_CadastrarPdv, L("TituloCadastrarPdv"));
If you don't need to use MultiTenancy, you can disable it on:
YourProjectName.Core\YourProjectNameConsts.cs there you'll find a variable
public const bool MultiTenancyEnabled = true; change it to false if you don't need to use it.
You can call ready the entire documentation for Authorization here:
AspnetBoilerplate - Authorization

Spring MVC Converter and Swagger doc: how to?

I use converters in my Spring MCV controllers. In this example, the String from the path variable is mapped into a UserId:
#GetMapping(path = "/user/{user-id}")
public User get(#Parameter(description = "User id", required = true, example = "3fa85f64-5717-4562-b3fc-2c963f66afa6")
#PathVariable("user-id")
UserId userId) {
return userService.get(userId)
}
It seems to annoy Swagger as the generated doc requires an object as parameter and not a plain string:
...
"/api/v1/user/{user-id}": {
"get": {
"operationId": "get",
"parameters": [
{
"name": "user-id",
"in": "path",
"schema": {
"$ref": "#/components/schemas/UserId"
},
}
],
...
with the UserId schema:
"UserId": {
"type": "object",
"properties": {
"value": {
"type": "string",
"format": "uuid"
}
}
}
And thus the Swagger UI cannot be used because either the parameter is considered as invalid when a single string is provided, either the data is actually invalid when the object format is used.
What is an option to fix that?
To achieve that, the schema parameter of the #Parameter annotation is the answer.
The above example becomes:
#Parameter(description = "User id",
required = true,
schema = #Schema(implementation = String.class), // this is new
example = "3fa85f64-5717-4562-b3fc-2c963f66afa6")

Getting access token claims in claims principal in IdentityServer4

I'm trying to get my head around oAuth2/IdentityServer4.
Using the sample application at
https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/3_ImplicitFlowAuthentication
The following code in the MVC application:
#foreach (var claim in User.Claims)
{
<dt>#claim.Type</dt>
<dd>#claim.Value</dd>
}
Returns what appears to be identity token claims
nbf
1467173142
exp
1467173442
iss
http://localhost:5000
aud
mvc
nonce
636027699106782287.MDI0YzI5MTQtYmQxNy00MDllLWJmYzQtZjBhYzI2MGNjYmE3MDFmNzg1YmUtM2Y5ZC00YjBiLWEzOGItN2Q3ODRiODJlYjFl
iat
1467173142
c_hash
H2i5QeJKlHM5-s8vUTYlOw
sid
42b58d38e2b7c6cc653492742a08840b
sub
818727
auth_time
1467170555
idp
idsvr
name
Alice Smith
given_name
Alice
family_name
Smith
website
http://alice.com
amr
pwd
The following code in the API project
var claims = User.Claims.Select(c => new { c.Type, c.Value });
return new JsonResult(claims);
Returns what appears to be access token claims
{
"Type": "nbf",
"Value": "1467173142"
},
{
"Type": "exp",
"Value": "1467176742"
},
{
"Type": "iss",
"Value": "http://localhost:5000"
},
{
"Type": "aud",
"Value": "http://localhost:5000/resources"
},
{
"Type": "client_id",
"Value": "mvc"
},
{
"Type": "scope",
"Value": "openid"
},
{
"Type": "scope",
"Value": "profile"
},
{
"Type": "scope",
"Value": "api1"
},
{
"Type": "sub",
"Value": "818727"
},
{
"Type": "auth_time",
"Value": "1467170555"
},
{
"Type": "idp",
"Value": "idsvr"
}
Notice the code is essentially the same (return claims in the user identity principle) and lack of name/email but the inclusion of scope claims in the API example.
The token flow is essentially IdentityServer4 => MVC Project => API Project. Obviously the MVC project has both the identityToken and access token but it's not load the access token int User.Claims.
My goal is to have the scope claims available in User in the MVC project so that I can setup policies to work the Authorize attribute section off my MVC methods.
Startup for the API project is here: https://github.com/IdentityServer/IdentityServer4.Samples/blob/dev/Quickstarts/3_ImplicitFlowAuthentication/src/Api/Startup.cs
Startup for the MVC project is here:
https://github.com/IdentityServer/IdentityServer4.Samples/blob/dev/Quickstarts/3_ImplicitFlowAuthentication/src/Api/Startup.cs
Thanks,
dave
The question is kind of invalid, but I'll leave it here with reasons why and a solution to save others time.
Firstly, there are two tokens for two different purposes.
The Access Token: Describes the client, which is the software that uses the API. Any claims in here are granting the client access to API endpoints.
The Identity Token: This describes the User, or the human that uses the software that uses the API.
The original question was asking how to view Client related scopes in an Identity token, which obviously isn't valid.
However, you can include Identity scopes in an Identity token.
To do this, set Type to ScopeType.Resource and set IncludeAllClaimsForUser to true, as follows
new Scope()
{
Name = "ManageUsers",
IncludeAllClaimsForUser = true,
Type = ScopeType.Resource
},

Spring Data ElasticSearch Build In IN query returning partial match

I am new to elastic search spring data, Today I was trying to get In query working with Spring data ES repository.
I have to do a lookup for list of user names, and if its exactly match in the index, need to get those users back as result.
I tried to use the built in repository 'In' method to do so, but it returns partial matches, please help me to make this working like SQL IN query.
Here is my repository code:
public interface UserRepository extends ElasticsearchRepository<EsUser, String>
{
public List<EsUser> findByUserAccountUserNameIn(Collection<String> terms);
}
REQUEST:
{"terms":["vijay", "arun"], "type":"NAME"}
RESPONSE:
[
{
"userId": "236000",
"fbId": "",
"userAccount": {
"userName": "arun",
"urlFriendlyName": "arun",
},
"userProfile": {
},
"userStats": {
}
},
{
"userId": "6228",
"userAccount": {
"userName": "vijay",
"urlFriendlyName": "vijay",
},
"userProfile": {
},
"userStats": {
}
},
{
"userId": "236000",
"fbId": "",
"userAccount": {
"userName": "arun singh",
"urlFriendlyName": "arun-singh",
},
"userProfile": {
},
"userStats": {
}
}
{
"userId": "236000",
"fbId": "",
"userAccount": {
"userName": "vijay mohan",
"urlFriendlyName": "vijay-mohan",
},
"userProfile": {
},
"userStats": {
}
}
]
This is because your userAccount.userName field is an analyzed string, and thus, the two tokens arun and singh have been indexed. Your query then matches the first token, which is normal.
In order to prevent this and guarantee an exact match you need to declare your field as not_analyzed, like this:
#Field(index = FieldIndex.not_analyzed)
private String userName;
Then you'll need to delete your index and the associated template in /_template, restart your application so a new template and index are created with the proper field mapping.
Then your query will work.

Resources