I apologise if the title is a little confusing, but I was a little stuck with the wording.
I'm currently working on a section of an application to allow users to grant developers access to their data through the application. This comes in a little 'Allow Some great app to access your account with the following permissions'. The application developer adds the required permissions, then when the user goes to authorize the application, these permissions are are displayed. If the user is happy to grant these permissions, the user shall press 'Grant'. This means that the user has agreed to every permission that has been displayed, and therefore this generates an API access token for the relevant application.
The issue now is that it has came to the attention that people may want to remove these permissions at a further date. At the moment, if the user would like to remove permissions, all permissions will be removed or disabled. The reasoning behind this is that if a single permission is removed from the application, the token that they authorized with is technically invalid as it does not have the permissions that were given to it when first creating the token.
Whilst this seems logical, there are also circumstances where the user would want to deny access for the third party application for a single feature (eg. The external application had a bug that was creating bad behaviour in a certain area, but was working fine in another area).
Would anybody be able to throw their two-cents in to this, as I'm having a hard time understanding if its best to allow modifications to a single permission in the event of problems, or to simply have to disable the application.
Related
The bounty expires in 4 days. Answers to this question are eligible for a +200 reputation bounty.
Pete is looking for an answer from a reputable source.
I am aware the user impersonation question has already been asked several times.
Unfortunately, none of the questions I read so far provided a reproducible guideline or overall concept how to do this in a secure way. Since every action needs to be logged, I can't use a hack to do this.
For that reason, I would like to kindly ask the community once again for advice and sanity check of my own ideas. Also, new approach suggestions are warmly welcome.
The questions I read so far include:
IdentityServer4 - How to Implement Impersonation
Allow supporter to sign in as another user
Impersonate with IdentityServer, with having an actor claim for the impersonated user
Identityserver3 - User Impersonation
Introduction
Basically, I have an ASP.NET Core Razor Pages app and an ASP.NET Core Web API, both protected by Duende IdentityServer.
Support Engineers need to be able to impersonate customers for service reasons ONLY after the customer consented to impersonation.
Basic work flow:
in the Razor Pages app, the customer activates "Grant Impersonation Permission" under his/her personal settings
impersonation permissions are valid for a maximum of 7 days
customers can revoke impersonation permissions at any time
Support Engineers are then able to log in as any customer that granted impersonation permission at the back office (without the customer being present, no remote-desktop style)
Approach 1:
When the customer grants permission, use the Token Exchange mechanism to exchange for a new access token with a life time of 7 days.
Store this token in a database in IdentityServer and allow only Support Engineers to get a customer's access token via a Controller using the customer's ID, name etc.
While this would work, I'm not comfortable with the idea of storing long-lived access tokens.
Approach 2:
When a Support Engineer logs in, based on his identity, show a custom consent screen where customers can be selected for impersonation and then log in as the selected customer.
The Support Engineer would then get the access token as well as the ID token.
The biggest problem is:
Are there any extension points/mechanisms in IdentityServer to be hooked-in to control the sign-in process to kind of turn the sign-in process to log in the customer instead of the Support Engineer?
Is even possible to do this in IdentityServer?
Approach 3:
In Allow supporter to sign in as another user, user mackie pointed out a high-level view of a impersonation feature.
Here are the steps:
Navigate to client application Sign in using whatever credentials
Check if any impersonation permissions exist (how these are defined is entirely up to you)
Prompt for impersonation account selection (or just continue as self)
Sign in as the selected account (with record of original actor)
Redirect to authorize endpoint
Issue tokens and redirect back to client application
How are steps 4. to 6. done in practice? Any suggestions on that?
I have a question about the problem in your Approach 2. The essence of user impersonation is actually to use "pseudo-token" to impersonate a user to verify some operations or permissions. Or maybe you just want to log all actions performed by the impersonated user?
I think maybe you can intercept on login like in this link. But I think it may be better to add some specific identification to it when the interception is successful, instead of directly using the user's information to log in. I think logging in the customer instead of the Support Engineer might not be a user impersonation anymore (just a personal opinion).
In addition, acr_values is mentioned in the link you provided. From your description, acr_values seems to have some fit:
acr_values allows passing in additional authentication related
information - identityserver special cases the following proprietary
acr_values:
idp:name_of_idp bypasses the login/home realm screen and forwards the
user directly to the selected identity provider (if allowed per client
configuration)
tenant:name_of_tenant can be used to pass a tenant name to the login
UI
For the usage of acr_values, you can refer to this link.
Other link:Impersonation workflow.
This is just my understanding and a suggestion, if I have any understanding wrong, please correct it.
I am trying to implement a hardware busy light to show my Microsoft Teams presence so that my family to not enter the room I have the office while I am in a meeting. I am looking to implement something similar to:
https://www.eliostruyf.com/diy-building-busy-light-show-microsoft-teams-presence
https://blog.jongallant.com/2014/12/beakn-v0-1-diy-lync-status-light/ (older acticle - similar idea).
The only problem I have with this setup is that I cannot get the MS Teams status.
The best way to go is by using MS Graph Presence API but my problem is that this is a company account and I don't have (and there is no way I could have) and app in the main subscription granted with the required scope: Presence.Read.
So I tried different ideas but none worked in the end:
check local running processes
check if MS Teams exposes any local API
check if there is a CLI available
This seems a simple idea, I mean, I see the status right there now while I am typing this message, I could as well do an app that gets a screenshot of the taskbar and extract the status from the icon, but is that really the only option I have?
I think I found something interesting for you.
Go to
C:\Users\user\AppData\Roaming\Microsoft\Teams
you'll find a file called logs.txt
In this file you see if your current state changed
(current state: Available -> DoNotDisturb)
I would write a script with php or VB (depends on your skills) that read that logs.txt file like every minute and check for the last "current state" line.
What those posts are doing (certainly the first one, I didn't check the 2nd one) is calling the Microsoft Graph, which has a "presence" endpoint to get a user's status. There's actually even a specific "/me" endpoint, to get your own personal preference (less access rights needed). See more about this here: https://learn.microsoft.com/en-us/graph/api/presence-get?view=graph-rest-1.0&tabs=http
In order for this to work, as you've mentioned, you do need to have an Azure AD App registration. However, importantly, this will only require "delegated" permission (i.e. only permission from the single user, you, to access just data for that single user, you). As a result, you can use "delegated" and not "Application" permissions, which means that it does -not- require Admin consent for the tenant.
It -does- require and Azure Add Application though, at the risk of stating the obvious. While you don't have tenant admin rights, you need to see if you have Azure rights, just to create an application (you might have this anyway as a developer in your org). If you don't even have this, you can sign up for an M365 Developer account, and use that tenant. Importantly - the application does't have to be in the same tenant. If it's not, it's just a simple multi-tenant app, like any 3rd party Azure AD-backed application is.
I wrote an app script which provides a web UI for data entry into a team calendar. I published it using G-Suite super admin account and added it as Trusted App under Security/API Permissions. "Trust domain owned apps" is checked under "Internal App Settings".
When a G-Suite user in our organization tries to access the app, he sees
"The developer of ShiftSchedulingApp, admin#_our_organization_.org, needs your permission to access your data on Google."
Those brave enough to click "Review Permissions" are taken to the next message:
"ShiftSchedulingApp wants to access your Google Account. See, edit, share, and permanently delete all the calendars you can access using Google Calendar"
Of course nobody wants to risk losing all the calendars on their Google Account and this is where it ends.
How do I get rid of this misleading message? It's not Google account, it's their organization account on G-Suite. It's not all their calendars, it's the shared team calendar only. It's adding data, not permanently deleting calendars. It's published by their administrator in their G-Suite, not an unknown 3rd party.
I spent days trying to make this message go away but no luck. App must be executed as an accessing user and not as publishing user because their user ID determines what shifts they can fill on a calendar.
I'd appreciate any hints pointing me the right direction.
I experimented with variations of the two-app approach as suggested.
The app which provides the UI needs to read the calendar to display available shifts - so I can't get away from the user authorization prompt.
Another variation I tried was having one app do everything and run as me, and another do nothing but return Session.getActiveUser(). I tried calling the 2nd one from the 1st one on the client side via XMLHttpRequest. It would be ideal for my needs - but I hit CORS error as apps URL is script.google.com but it actually gets redirected to script.googleusercontent.com. There doesn't seem to be a way to set CORS in Google App Script.
Although I was not able to find a way to avoid prompting users for authorization when executing the app as accessing user, it turns out my reasons for doing that were based on a false premise.
I chose to publish app as accessing user because I thought that's the only way to get accessing user Id - which is true for non-G Suite accounts.
However, when app is published by a G Suite account, the app can get accessing user ids within the same G Suite domain even when it's set to execute as publishing user.
Thanks Niek and TheMaster for your help!
If you just need user ID, why do you ask for all those permissions?
Possible Solutions:
2 web-apps- One running as you and another as user accessing (with only profile) permission. The second one will be the actual web interface and POST necessary information to the first one with privileges. OR
Implement your own web-app Google-sign in1
Use the least permissive2 scope3
I've updated my app to use the new Box V2 API instead of the old Box V1 API.
I have only one question left : After revoking access to an app ( http://developers.box.com/wp-content/uploads/2013/08/Provision-Reject.png ), why is it required to grant access again after giving the password again?
Thanks for your answer in advance!
When a user decides to revoke access to an application, they've basically decided that they don't trust that application to get to their Box content. If they change their mind and want the application again, then the user should know what kinds on things your application can do.
The "grant access" screen is part of the OAuth2 specification, and is used by just about every website these days that lets applications get at user's accounts. Android apps have a similar "grant" screen to say stuff like "This application wants to get at your address book, send emails, and ... only use it if you trust the application to do these things."
I could be wrong about this, but it is my understanding that it is a very common practice to handle permissions like so:
The user goes to the login page and provides a username and password.
The username and password are verified. If valid, the user's information (including permissions) is set to a session variable.
As the logged in user navigates the site, certain features are available to the user based on their permissions, which are referenced in the session.
This makes sense since it would be impractical to frequently query the database for the user's permissions. However, from a security standpoint, I'm not sure what the best approach is. A simple example would be if you were to remove a certain permission from a user while they're logged in. An extreme example would be if you were to mark a user account as inactive while they're logged in. I don't know how you could get that user's web browser to know about the change other than to code database permission checks (as opposed to session permission checks) into every part of the website. Again, that seems like overkill, but is that really the only way if you want a secure website?
Thanks!
I believe you've got it stated correctly:
I don't know how you could get that user's web browser to know about the change other than to code database permission checks (as opposed to session permission checks) into every part of the website.
Depending upon how your site is designed, it might make sense to invalidate the user's session when you perform drastic enough modifications to the user's privileges. Deleting sessions mean the user will be faced with a new request to log in, but if you've just disabled their account or severely downgraded their privileges, that might be acceptable.
But you wouldn't want to invalidate the session for every little thing and certainly not for almost any permission enhancement operations.
If you expire all sessions N seconds after the last authentication you can place an upper limit on the amount of time that your application code would grant permissions that have actually been revoked. This might be suitable when the stakes are not very high anyway.