Access control in LoopBack - angularjs

I am building an events management web app for my clients based on StrongLoop API platform whereby I need to limit CRUD access to data to the currently logged in user (a client).
I have followed these tutorials https://github.com/strongloop/loopback-faq-user-management, https://github.com/strongloop/loopback-example-access-control to successfully login and logout, and now need to implement bringing back the correct data on the AngularJS client.
I have setup a relation on my 'events' model as follows:
"relations": {
"user": {
"type": "belongsTo",
"model": "User",
"foreignKey": "ownerId"
}
}
and also on the built-in User model:
"relations": {
"events": {
"type": "hasMany",
"model": "event",
"foreignKey": "ownerId"
}
}
Not sure where/how to define the access token after login to make API calls. Do I also need to apply a filter on $scope.events = Event.find(); to retrieve only the records where ownerID: <currentUserId> or should the ACLs achieve that for me?
Any help much appreciated.

1) Access token automatically saved to localStorage/sessionStorage and to angular-sdk internals. So it attached to authorization header on every request to API.
2) Yes, you should apply filter, because ACL just allow or deny access to remote methods. By the way, another way to query user's events is
User.events({id: currentUserId})

Related

Azure Access Package direct assignment with approval

In the Azure Portal, I can navigate to Identity Governance | Access Packages | Access Package and then create a direct assignment for a user. The Azure Portal allows me to specify whether or not approvals are applied to the assignment request.
I can also create a direct assignment request using the Microsoft Graph, but I cannot figure out how to apply approvals to this request. Requests from the Graph seem to always bypass the approval policy.
Using Fiddler and the Azure Portal (ref screenshot above), I can see that the following JSON payload is POSTed to the Graph. So I took that exact same JSON payload and POSTed it with the Graph Explorer, but the approval process is still being bypassed.
POST https://graph.microsoft.com/beta/identityGovernance/entitlementManagement/accessPackageAssignmentRequests
{
"accessPackageAssignment": {
"target": {
"objectId": "5eaf3cdc-3859-40a1-bd48-583da94d16b3",
"type": "User"
},
"assignmentPolicyId": "3261eff8-1e91-426d-93dd-55f196a593a4",
"accessPackageId": "d14d6f8c-458f-4a1c-926a-38f4c5e63fe8"
},
"justification": "testing",
"requestType": "AdminAdd",
"parameters": [
{
"name": "IsApprovalRequired",
"value": "true"
}
]
}
How can I achieve the same behavior as the Azure Portal (i.e., direct access package assignment with approval)?
In the request body, it contains a accessPackageAssignmentRequest object which has a property assignmentPolicyId, and the assignmentPolicyId property identifying the accessPackageAssignmentPolicy, and this policy has a definition for requestApprovalSettings. approvalSettings contained isApprovalRequired.
By the way, what you mentioned are beta version api which is not recommended. And V1.0 version may be better.

How to use ARM templates to deploy a roleAssignment for an App Registration Service Principal?

In my current project I'm working with pre-created App Registration Service Principals in Azure AD. I'm using an ARM template to create a StorageV2 account plus some blob containers, then create a roleAssignment giving Storage Blob Contributor rights to one of the Service Principals. The relevant section of the ARM template is at the end of this post.
What I've found is that if I take the ObjectId of a regular AD user, such as myself or my colleague, and set that as PrincipalId, the script runs correctly. However, I can't get this to work with a Service Principal.
If I use the Service Principal's ObjectId, then I get the following error:
Deployment failed. Correlation ID: 40e0c146-165a-47c0-b022-ac04781d8194. {
"error": {
"code": "PrincipalTypeNotSupported",
"message": "Principals of type Application cannot validly be used in role assignments."
}
}
Having spotted some suggestions for Azure Powershell users that I should use Application (Client) Id instead, I tried that, but get the following error (Guids redacted):
Deployment failed. Correlation ID: 5c725a51-230a-4d85-bb61-b2f4cdf849ff. {
"error": {
"code": "PrincipalNotFound",
"message": "Principal 9f****30 does not exist in the directory db****75."
}
}
So the ObjectId it can find but not use, and the ClientId it can't find.
I have found that if I use Azure Powershell and use the New-AzureRmRoleAssignment command, I can reproduce the PrincipalTypeNotSupported error by providing the Service Principal's ObjectId to the -ObjectId switch. However, that command also has a -ServicePrincipalName switch as an alternative, and if I give that the Service Principal's ClientId, it works!
Is there any equivalent of -ServicePrincipalName for the ARM templates, and if not, is there any other way to achieve this? I can use Azure Powershell as a workaround, but it's messier than I'd like.
If this is a feature gap, where's the best place to report it?
Relevant section of ARM template follows:
"resources": [
{
"name": "[variables('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"location": "[resourceGroup().location]",
"apiVersion": "2018-07-01",
"sku": {
"name": "[parameters('storageAccountSku')]"
},
"dependsOn": [],
"tags": {
"displayName": "Storage Account"
},
"kind": "StorageV2",
"properties": {
"accessTier": "Hot",
"supportsHttpsTrafficOnly": true,
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Deny"
}
},
"resources": [
{
"type": "blobServices/containers",
"name": "[concat('default/', variables('myBlobContainerName'))]",
"apiVersion": "2018-07-01",
"dependsOn": [
"[variables('storageAccountName')]"
],
"resources": [
{
"type": "Microsoft.Authorization/roleAssignments",
"name": "[variables('myRoleAssignmentGuid')]",
"apiVersion": "2018-07-01",
"properties": {
"roleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe')]",
"principalId": "[variables('myPrincipalId')]"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), '/blobServices/default/containers/', variables('myBlobContainerName'))]"
]
}
]
}
]
}
]
Finally solved this one thanks in part to the pointers from #4c74356b41.
When an Application Registration object is created, an identically named object is also created under Enterprise Applications. This has the same ApplicationId, but a different ObjectId, and it's the ObjectId of this Enterprise Application object that our ARM script needs.
You can find this object in the portal by going to the Application Registration entry, then clicking on the link after Managed application in...
Screenshot of App Registration with Link
Once you're on the corresponding Enterprise Application object, you can get the ObjectId from Properties, and use this the value for principalId in the ARM template.
At the time of writing, the Microsoft Documentation is a bit vague on this, with the terms Application and Service Principal seemingly overloaded. This article says that when you register an application you get an Application object and a Service Principal object, but doesn't use the phrase Enterprise Application once, or refer to App Registration objects per se, so it's unclear which is which.
I'm assuming Application == Application Registration and Service Principal == Enterprise Application. This SO post would seem to suggest this is the case, as would the solution above.

Tenant does not have a SPO license when updating user

I've been using Microsoft Graph API to create users in Azure Active Directory, but when I try to update skills or schools I get error:
PATCH https://graph.microsoft.com/v1.0/me
{
"skills": ["skills-value"]
}
{
"error": {
"code": "BadRequest",
"message": "Tenant does not have a SPO license.",
"innerError": {
"request-id": "804948b5-f087-4be8-bdf0-ab49dccf7efc",
"date": "2018-04-14T17:55:52"
}
}
}
Also when I try to update for example businessPhones it's work fine, I get no errors.
PATCH https://graph.microsoft.com/v1.0/me
{
"businessPhones": ["businessPhones-value"],
}
HTTP/1.1 204 No Content
Any idea?
The Microsoft Graph is a front-end which intelligently wraps a suite of Microsoft and Office 365 APIs into a single endpoint. This includes free and paid services, and ultimately to access certain APIs you will need to have a subscription for the services which host the underlying API.
In this case, you are seeing that the skills attribute on the user is stored in SharePoint Online, and if you do not have a SharePoint license, you will not be able to use that property.
If you are simply looking for a way around this, you might look into storing and retrieving your skill information using Add custom data to resources using extensions which is stored in Azure AD and should be totally free to access.

Microsoft Graph, Registering a Schema Extension

I'm building an internal meeting room app that uses the Microsoft Graph API and I would like to extend Event objects with a Schema Extension.
Documentation:
API Reference
Tutorial Example
However when running a query to register a new schema extension, I am receiving this HTTP response:
{
"url": "https://graph.microsoft.com/beta/schemaExtensions",
"status": "403 Forbidden",
"headers": {
"request-id": "e1e36210-6c4c-4ed8-afb1-c9ee6f6362ed",
"client-request-id": "e1e36210-6c4c-4ed8-afb1-c9ee6f6362ed",
"x-ms-ags-diagnostic": "{\"ServerInfo\":{\"DataCenter\":\"North Europe\",\"Slice\":\"SliceA\",\"ScaleUnit\":\"001\",\"Host\":\"AGSFE_IN_2\",\"ADSiteName\":\"DUB\"}}",
"duration": "742.4624"
},
"body": {
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"request-id": "e1e36210-6c4c-4ed8-afb1-c9ee6f6362ed",
"date": "2017-05-10T10:05:37"
}
}
}
}
I can confirm that my application has the prerequisite scope permission of Directory.AccessAsUser.All and it's also been more than 16 hours since adding this permission. I have also got verified domains, so the namespace should be OK per the documentation reference.
My API query in code:
Outlook.test({
version: 'beta',
resource: 'schemaExtensions',
method: 'POST',
body: {
id: 'thehivegroup_beethere',
description: 'Extension for event presence status',
targetTypes: [ 'Event' ],
properties: [
{ name: 'checkIn', type: 'String' },
{ name: 'checkOut', type: 'String' }
]
}
})
.then(result => console.log(result), err => console.error(err))
Which results in a POST with the JSON encoded in the body and headers with authorization token to the URL https://graph.microsoft.com/beta/schemaExtensions.
I have tried different IDs, such as beethere, which resulted in a namespace error, so I know this ought to be working fine.
There are no other scope permissions I am aware of that I need to enable here as well. The error is just too vague for me to figure out what privileges are insufficient here.
EDIT: Have manually run the query in the Graph Explorer as an Admin in the tenant, added the scope permissions required for the API and some extra ones in case, but the query for registration of Schema Extensions still does not work, with the same error message as the application receives. So it is definitely not a problem in my code, but the Microsoft Graph API. Is there a contact or way to ask microsoft to look into the issue?
Directory.AccessAsUser.All is a delegated permission only (it must be delegated because it grants access to directory based APIs as the signed-in user's access rights). It doesn't show up in the roles claim because it isn't an application permission.
As far as I know, right know, you cannot use the application flow (client credentials) to create a schema extension, and you need to use the "code authorization" flow. Please let us know if this is a requirement. Additionally we'd love to know if you want to see an experience for schema definition registration as part of the application registration...
Also you CANNOT currently create a schema extension definition (or manage it) through Graph Explorer. For you to created a definition, you must either be an admin or the owner of the app creating the extension definition AND the creation request must also come from that application (which cannot be graph explorer). We may look at relaxing this last constraint.
If you want to see a code snippet for this it's available here (although it's a UWP c# app, not JS): https://github.com/microsoftgraph/uwp-csharp-snippets-rest-sample.
Also schema extensions is now GA, and available in the v1.0 endpoint.
Hope this helps,
Graph Explorer is able to add an extension.
You will need to create an app in your tenant and set the owner in the payload to the client id of your app.
more on this
This schema extensions creating REST works well for me. Please ensure that the token contains Directory.AccessAsUser.All permission. You can parse the token check the scp claim in it from this site.

Role/Group based Authorization using ADAL.js and ASP.NET Web API

What we are planning to achieve is a role-based security for a Front end Angular-2 and back-end ASP.NET Web API application. We are doing the authentication process with the help of ADAL.js and storing the token in the local storage. We have also implemented the approach shown here i.e. to call the Graphi API and get the user groups to stuff them into Claims.
My question is : Is there anyway, we can add role claims from server to the bearerToken which is residing in the local storage. Or is there any better way to approach this issue.
The code sample mentioned assign the role based on the group. If you have the Azure AD basic version, it support to assign the role to the users/groups directly.
My question is : Is there anyway, we can add role claims from server to the bearerToken which is residing in the local storage. Or is there any better way to approach this issue.
Yes, it is possible. To issue the role claims we need to assign the users to assign the roles to users or group first. Then when the user acquire the token, the Azure AD would issue the relative role claims in the token.
You can refer the code sample for using the role claim from here.
And you may also be interest in groups claim developing.
ok i was struggling with this for a while and i have figured it out i believe.
First,
In Azure AD, set up your WebApi app as application type to be Web App / API.
go to Manifest file and add your roles like
[
{
"allowedMemberTypes": [
"User"
],
"displayName": "Reviewer",
"id": "0238c2bb-9857-4d07-b760-a47ec621d57a",
"isEnabled": true,
"description": "Reviewer only have the ability to view tasks and their statuses.",
"value": "reviewer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Approver",
"id": "000018cb-19e3-4f89-bf99-5d7acf30773b",
"isEnabled": true,
"description": "Approvers have the ability to change the status of tasks.",
"value": "approver"
}
]
Then create the the Client app as Application type to be Native app and add required permissions to the service you added above.
In the SPA Angular app add something like this
var endPoints = {
// "https://localhost:44386/" is the API URL
// "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" is the Service Application ID
"https://localhost:44386/": "xxxxxxxxxxxxxxxxxxxxxxxxxx"
};
adalAuthenticationServiceProvider.init({
instance: "https://login.microsoftonline.com/",
// tenant is your tenant name (something like below)
tenant: "{NAME}.onmicrosoft.com",
// this is the Native app application ID (ClientID) you registered
clientId: "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
extraQueryParameter: "nux=1",
endpoints: endPoints
}, $httpProvider);
}
]);
Then, in your startup.cs you need to set up the Service App like the following:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters
{
/* "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" is the Service Application ID. (Same as you registered in the client app above)*/
ValidAudience = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
RoleClaimType = "roles"
},
/*enant is your tenant name (same as you registered in client app above)*/
Tenant = "{NAME}.onmicrosoft.com"
});
Finally you need to go to Azure active directory => Enterprise application => all applications => select your webAPI service => Users and groups => then assign users to the roles.
When this is all done when you log through your client app to authenticate and call the webapi, adal.js and ada-angular.js will put the proper bearer token that contains roles
Good to learn this approach.
Ted, thanks for sharing your solution !
For those who are not familiar with operating Azure AD manifest file. The following is a good resource.
https://thinkthencode.wordpress.com/2016/04/24/azure-ad-using-app-roles-for-authorization/
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Reviewer",
"id": "0238c2bb-9857-4d07-b760-a47ec621d57a",
"isEnabled": true,
"description": "Reviewer only have the ability to view tasks and their statuses.",
"value": "reviewer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Approver",
"id": "000018cb-19e3-4f89-bf99-5d7acf30773b",
"isEnabled": true,
"description": "Approvers have the ability to change the status of tasks.",
"value": "approver"
}
]

Resources