Get shared calendar from different user(meeting room) - c#

// How to get different user / meeting room calendar events?
We are trying with the graph REST API to get calendar events of another user (shared calendar to the authenticated user) or a meeting room (should be an Active Directory user with shared calendar to all users within the organization).
We still get "Forbidden" response.
We can successfully get the user(himself) authenticated calendar events.
We can also get user details of the authenticated user and even of another user (user authenticated as John.Doe#company.com and can get user details of elise#doe.company.com) but we cannot get details of the meeting room user even though it should be a normal user in our AD.
We tried to setup all delegated and even app permission scopes, nothing helped.
Example:
var endpoint = "https://graph.microsoft.com/v1.0/users/"+userId+"/calendarView";
Is there a way to retrieve this information?

The problem is that your token does not have the correct scope. To be able to access shared calendars, you need the Calendars.Read.Shared (or Calendars.ReadWrite.Shared). How you get that scope into your token depends on where you registered the app (which answers your first question!)
Does it matter where or how the application was registered?
Yes, this matters. Both methods will work, but where you register affects how you request authorization and tokens. Also, apps registered in Azure Management Portal can only authenticate Office 365 users, not Outlook.com users. More on this in #2.
Does it matter what authentication URL we use?
Yes! The URL you use is directly related to which place you registered your app. I'm going to break this down below.
App scope permissions vs delegated scope permissions - does it matter which ones we set up in the application? Will our desired functionality work with delegated permissions?
Yes it matters. App permissions are granted to the app, and for Outlook APIs, these are global to the entire organization. So if you grant an app Mail.Read, it can read mail for all users in the org. The app acts as itself, and does not authenticate a user. Because of this, the auth method requires a certificate instead of a client secret. This method is meant for daemon-type apps. You most likely want delegate permissions since you want to authenticate users and then give them access to just those other mailboxes/calendars they are allowed to view.
Do AD permissions somehow influence the permissions user has in the application?
Well yes, in the sense that if you include a .Shared scope in your permissions, what the user has access to is set by what other users have shared with them (and this ties back to AD).
How do I add a shared scope
As I said above, this matters on how you registered your app.
Azure Management Portal
Apps registered in the Azure Management Portal use the "v1" version of Azure's OAuth2 implementation. Under this model, you have to specify the permissions for your app "up front" on the app registration itself. To add a shared permission, you have to modify the app registration in the portal. The permissions are shown in the portal as "Read user and shared calendars" (for Calendars.Read.Shared) and "Read and write user and shared calendars" (for Calendars.ReadWrite.Shared).
If your app is registered here, then you MUST use the v1 auth and token endpoints:
https://login.microsoftonline.com/common/oauth2/authorize
https://login.microsoftonline.com/common/oauth2/token
Additionally, under the v1 scheme, if you add new scopes to your app registration, you MUST have the user's reconsent. Otherwise, the next time they sign in to your app, they will just get the same permissions they had before. To do this, when sending the users to the authorize endpoint, add a prompt=consent parameter to the authorize URL.
Application Registration Portal
Apps registered here use the v2 Azure implementation and gain a few benefits. First, you can authenticate Microsoft accounts (Outlook.com) as well as Office 365 users. Second, adding scopes doesn't require modifying your app registration. And last, you don't have to manually reconsent users, the auth endpoint will detect the change and prompt for you.
Apps registered here use the v2 auth and token endpoints:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
https://login.microsoftonline.com/common/oauth2/v2.0/token
Scopes are specified in the scope URL parameter in the auth endpoint. So to add the shared scopes, you would just replace your existing Calendars.Read and/or Calendars.ReadWrite with the .Shared equivalent.

Related

Authenticate an EWS application by using OAuth with Permission control

I want to have a windows service that can received unread mail from my O365 account every 3 minutes and have different action depends on Mail subject. I choose EWS managed API instead of Graph is because maybe I would use this program on Exchange Server in the future. I'm following this tutorial Authenticate an EWS application by using OAuth and I have some question about permission control, in this case I use Application permissions which run without a signed-in user present. for example, apps that run as background services or daemons and can access multiple mailboxes.
Now I can access my mailbox with the applicationID, tennatID and Client-secret. But I have to inpersonate someone within my tennat(domain) and than I can send mail by the Mail Account. My question is Is it have any permission control can set that this application only can access or inpersonate part of tennat user rather than all user within my tennat? (in Azure AD Api permission setting I only seen full_access_as_app - Allows the app to have full access via Exchange Web Services to all mailboxes without a signed-in user.) I think its not make sense if this application have permission that can impersonate ALL user of my organization, that would be a big deal if this application client-secret exposes.
Sorry for my poor English.
You can use Application access policies to scope your application so it only has access the mailboxes it needs. see https://learn.microsoft.com/en-gb/graph/auth-limit-mailbox-access.

Microsft Graph API Access Token

When I use the graph explorer (https://developer.microsoft.com/en-us/graph/graph-explorer) to call graph API (like teams api), it automatically provides me with an access token which has the permissions and authentication to do tasks (such as creating a team and adding people).
However, when I try to search for a way to get a access token (https://learn.microsoft.com/en-us/graph/auth-v2-user), it seems to be the case that I would have to register an app with Azure AD (which to begin with only has Read permissions and would not allow me to create teams for example), and follow more steps to get an access token.
My questions is, why is this the case that the access token that is provided through graph explorer lets me do everything while I have to go through so many more steps to get a token by myself (such as creating an app, requesting permissions, and then getting the token). Or is there a simpler way to get access to the access token (with me as the user) that I am not aware of to use graph API?
That's because Graph Explorer is also registered as an application and exists as a service principal/enterprise application in your Azure AD tenant.
Every single application that gets tokens from Azure AD must be registered as an app somewhere.
In case of multi-tenant applications like Graph Explorer, it is registered in one tenant and a local representation of the app (a service principal) is created when the first user consents to permissions required by the app. (or it exists by default, some Microsoft apps exist in every tenant at creation time)

Google Calendar API. Adding an event to someone calendar throws error "Error 401: invalid_client" just when authenticating

I have a C# class library from which I am trying to add an event to someone calendar just by using his/her email address and password as credentials. So I debug it and once started a new page in the internet browser is open and below error is displayed:
Below the code:
// It crashes when calling GoogleWebAuthorizationBroker.AuthorizeAsync
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "myGoogleAccount#gmail.com",
ClientSecret = "myGoogleAccountPasswordHere",
},
new[] { CalendarService.Scope.Calendar },
System.Environment.UserName,
CancellationToken.None).Result;
// Create the service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Calendar API Sample",
});
Why this error is happening? ClientId is not the gmail account?
Also why a new page in internet browser is opened? I want to do authentication without opening a page in the internet browser because this class library is called from a windows service so I need authentication to be done in the background.
Answer:
In order to insert methods into a user's Calendar, you need the user to give your application permission to make actions on their behalf. This is done using a Google Cloud Platform (GCP) Project, with OAuth2 Authentication.
More Information:
Each application which runs and takes actions on behalf of a Google account user has to have the scope of its ability well defined so that it can't start doing things that a user hasn't given it permission to do.
For example: if you give an application permission to create Calendar events, you don't want it to be able to do other things such as read your emails or download the contents of your Drive.
In order to designate what your application has the power to do, it needs to be registered with Google. As you have already deduced in your question and comments, the Client ID and Client Secret required by an application connecting to a G Suite API isn't simply the username and password of a Google Account, but a designated ID-secret ID pair which is provided by Google to identify your application.
OAuth2:
OAuth2 is a specific authorisation framework. The framework is defined in RFC 6749 and sets out the process in which a user can authorise an application to access their account. The limit of the authorisation is defined by the scope of the application on authorisation, and can not be changed without explicit re-authorisation by the user.
Before continuing it's worth defining a few important terms here:
User:
A user is the person; the individual that has an account and gives permission for an application to take actions on their behalf.
Client or Application:
A Client or Application is a program which is designed to take actions over HTTP by connecting to a service's API. Applications can be mobile apps, web apps or desktop clients.
Authorisation Server:
An Authorisation server is a server which is separate from the servers that store user resources. It verfies the user's identity and provides a grant which can be used to get an access token to a resource server.
Resource Server:
This is the server where user data is stored. This could be anything from user information to files or emails.
The authorisation flow has already been well documented, but for the sake of this scenario we can abstract it down to the following steps:
An Application wishes to take an action on a resource server on behalf of a user.
The Application makes an authorisation request to the user. This is generally presented as a login page for the account for which the application is accessing.
The user logs in to their account and is presented with an OAuth consent screen - this contains information such as the application's name, and the list of tasks that it is requesting authorisation for. These are often generic, and will say something like See and download all your Google Drive files or View and edit events on all your calendars. This allows the user to know what they are authorising before they confirm.
An Authorisation Grant is given to the application.
The Application provides the obtained authorisation grant along with its assigned client credentials to an authorisation server.
On verifying that both the user's grant and the client's credentials are correct, the authorisation server returns an access token which can be used to access the requested and approved resources. Note: This is normally all handled by your client library for whichever language you use.
The Application can now make a request to the resource server, providing the access token obtained from the authorisation flow. It is at this point that the permitted resources can be accessed.
Google Cloud Platform Projects:
A GCP project what Google sees as your application. The registration for your application is required to be able to obtain the client ID and client secret which your application will need in order to get an access token in the authorisation flow.
In the GCP console you can set up all the required services that your application needs. Each API you wish to use has to be enabled for your application, as there are many Google services with APIs and they are disabled by default.
Once a GCP Project has been created, you can use the API Library (From the ≡ > APIs & Services > Library menu item on the left) to find and enable the API. Note that for your use case you will want to enable the Google Calendar API and not the CalDAV API.
You will also need to set up a consent screen before obtaining credentials for your application. An OAuth consent screen is what your users will be presented with in the first step of the OAuth flow:
When setting up your OAuth consent screen, you will need to provide the following information:
Application type (public or internal to your domain)
Application name
The scopes that your application needs (explained in the next section)
After the consent screen has been set up, you can download the client credentials for your application. With these, your application has permission to run as a client, but each user that has their resources accessed will still have to give their explicit permission to allow the application to do so.
Scopes:
Within a single API there can be many scopes of access - having read-only access to calendar events is vastly different to having complete read-write access to all calendars that a user owns. This is where scopes come into play.
A scope is defined as its namesake; that is to say, a scope defines the scope of access an application has to a service. Even though an entire API has been enabled for a project doesn't mean that you need to use all features of the API. For this reason, scopes need to be defined.
Scopes are defined in the application itself before making the initial request for the user grant. In C#, for example (taken from the .NET Calendar API Quickstart):
// scopes are defined as an array of strings:
static string[] Scopes = { CalendarService.Scope.CalendarReadonly };
...
UserCredential credential;
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
The access token that is stored is based on the scopes that were defined in the call. If a method is called which needs a different scope to those which the token grants access to, the call will fail with a 403: Unauthorized error. The required scope will need to be added to the application, the old access token deleted and the user will need to grant permission for the new scopes.
Service Accounts:
As well as regular users, there is another special type of Google account called a Service Account. From the documentation:
A service account is a special kind of account used by an application or a virtual machine (VM) instance, not a person. Applications use service accounts to make authorized API calls.
Normally, every user for whom you wish to perform tasks or access resources needs to give explicit permission for your application to do so. For G Suite domains, however, you can use a service account with domain-wide delegation to complete tasks on behalf of users without the requirement.
Service accounts use a special kind of service-account credential which can be created in GCP and used in your application. Rather than making a UserCredential object, a ServiceAccountCredential is needed which doesn't require involvment by an end user.
When running a service account on behalf of a user with domain-wide delegation, the name of the user needs to be specified in the delegated credentials so the application knows which user in the domain to run as. If a user is not provided, the service account will run the code as itself; which is useful in some cases but often times will not return an error and so it may not be clear for whom the operation was run.
Note: While Service Accounts can be created by anyone, domain-wide delegation of authority can only be accomplished for a G Suite domain, and not #gmail.com addresses. All Gmail account users must give explicit permission for an application to run on thier behalf as set out by the OAuth flow.
References:
Using OAuth2 to Access Google APIs | Google Identity Platform
RFC 6749 - The OAuth2 Authorization Framework
OAuth - Wikipedia | #OAuth2
Google Cloud Platform Console
Google APIs Explorer | Google Developers
.NET Quickstart | Calendar API | Google Developers
Service Accounts | Cloud IAM Documentation | Google Cloud
Perform G Suite Domain-Wide Delegation of Authority | Directory API
OAuth 2.0 | API Client Library for .NET
Related Questions:
Google API Service Account. Can only see service accounts drive even with Domain Wide Delegation Access
Creating events using the Google Calendar API and Service Account

Allow supporter to sign in as another user

We currently have an Identity server 4 application. Using entity framework core and asp .net identity.
We have a group of supporters who need to be able to access our users accounts in order to help them with issues over the phone. Our users are not able to figure out how to use team viewer. As most of them are mobile and will only have a cellphone at the time.
I know all the security ramifications of allowing other people to sign into your account however there is really no way around this. Our customers have accepted that our supporters can connect to their account when they request it. We trust that our supporters only do this when its requested.
Current solution and its issues
The current hack creates an api endpoint which only our supporters can use as it has been locked down so that only those with supporter permission can use it. They send the users email and we hack create them an access token which is then used by the application (Web version) to act like its the user who is having issues.
This solution was created by my predecessor basically by taking the supporters access token and replacing all of the claims with this supporters id to the users id and returning it to the application. I hate this solution on a number of levels and its very unstable every time i look at this method it breaks. currently its not working because audience clams are incorrect for some reason.
What i want to do
I would really like to do this in a less hack way. So is there a way to sign in a user to the application without it actually being them thats doing the signing in and return an access token?
I have tried doing
await _signInManager.SignInAsync(user, false, null);
But i cant seam to figure out how to get that to return an access token.
What i would really like to do is have the ability for supporters to login to any ones account but do it securely somehow.
The problem with the user account is that it's not bound to one application. So by allowing others to login using the account, you give them also access to other applications. As a workaround you could use 'public' accounts, like engineer_01, engineer_02, etc.
But, this may not be necessary at all. What you really want IMO is to impersonate the user, instead of 'hacking' the account.
One way to do this, is to extend IdentityServer with a custom grant type using extension grants.
How this could work:
A signed-in user, who is allowed to impersonate users for the particular client/resource, requests an access token at the new impersonation endpoint.
The user sends the sub from the user to impersonate to the endpoint, where the user and (combination of ) sub are verified.
When access is granted a new (short-lived) access token is returned which can be used to impersonate the user, without having to know the credentials of the user.
The access token should contain information of the endpoint so it can be determined whether the user is impersonated.
We implemented an impersonation feature that is integrated into the browser-based sign in flow. If a user with permission chooses to sign in as another user then we add additional claims to their IDS4 authentication cookie which then supports issuing extra claims in the resulting token that reflect that it's an impersonation session and who the original actor is.
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

Azure AD multitenant permissions

I have an Azure webapp that's managing it's users via Azure AD. I want the users to be able to register in my Azure AD directory to create an account (self-service), so I gave the app read-write access to the directory and setup a page using the Graph API to create the users.
Until here, everything is great. But the problem I have now is that I want to enable multi tenancy, so users of external AD directories can login to my app. This works, but I need to login as an administrator for the account because it also asks read-write access to their directory.
Is there a way to fix this? I only want read-write access to my directory to be able to create user accounts. I don't want to ask permission to touch their directory because, most probably, they wouldn't trust my app.
Thanks.
I found a quick and dirty solution: Add another app to the Active Directory. This app should be single tenant and have only permission to read and write the active directory. We can the use this app's credentials to access the Graph API and the other app's credentials to authenticate users.
I wait to see if someone has a better solution for this scenario...
sorry for the late response here. In general, an operation to create objects in a directory (like users) requires admin permissions. Also it looks like the web app you are creating uses app-only permissions, which definitely requires admin consent. In the multi-tenant case, the admin of the consenting tenant must be the one to consent to this type of app - only someone in this role really has the authority to grant consent for this level of access.
Hope the helps,
No need to use a secondary app in lieu of the authentication role - - there may be some peculiar side effects on the authenticating user anyway such as extraneous / incomplete logging, role inconsistencies, and missing system / internal references.
What are you using for login credentials for your app (TenantID etc.)?
AD is very strict in credential management, so I would go back to the app structure.
At the query level, you could make all tables entirely separate per tenant with no shared table data and include a multitenant identifier column so no one can sql inject if you were sure to include the multitenant identifier as an explicit variable.
Then in an entity model, you could inherit a multitenant interface for everyone which referred back to the tenant identifiers (as a part of EF).
This way the burden is isolated to OAuth or other libraries on top of that to take care of the third-party authentication.

Categories

Resources