How to access Exchange calendar from asp application - c#

I have been tasked with writing a .NET application that has to have access to a users exchange calendar. This application will only be accessed from the local network and I need to have to automatically use the current domain users credentials to access exchange.
I have the following code but I get an error saying "The account does not have permission to impersonate the requested user."
ExchangeService service = new ExchangeService();
service.UseDefaultCredentials = true;
string exchange = "exchangeWSURL";
service.Url = new Uri(exchange);
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.PrincipalName, userid);
service.PreAuthenticate = true;
CalendarView cal = new CalendarView(startDate, startDate.AddDays(7));
FindItemsResults<Appointment> findResults = service.FindAppointments(WellKnownFolderName.Calendar, cal);
It looks like I am doing something wrong. I was hoping to now have to turn on impersonation for all users on the domain.
Any help would be wonderful.

This article provides what you seem to be looking for. Take note of the paragraph on "Impersonation". This seems to suit your needs perfectly.
ASP.NET and Exchange tips and samples

Copied from MSDN:
You must configure the Exchange server to allow impersonation before
your application can use impersonation. For more information, see
Configuring Exchange Impersonation (Exchange Web Services).
https://msdn.microsoft.com/en-us/library/dd633680(v=exchg.80).aspx
https://msdn.microsoft.com/en-us/library/bb204095(exchg.140).aspx

Related

What permission is required to get the WorkHours of a calendar?

Background
I am trying to connect to Office 365, to read the calendars of users that have granted permission. I have tried two options:
Exchange Web Services (EWS)
Microsoft Graph
EWS works but has the downside that I use login/password combinations to connect. Even though I store them encrypted, I'd rather not store them at all.
Microsoft Graph works as well, but has a gigantic downside; any updates I make to an item using the API is sent to all attendees. This behavior can be turned off when using the EWS API, but not (yet?) for Graph.
I'd like to take the OAuth implementation I have for Microsoft Graph, and use the EWS service to connect. No updates to attendees unless users want them, and no stored credentials.
The problem
For my application to work properly, I need to;
Get the timezone of the calendar, which I do by reading the person's work hours;
Read and write calendar items, which is the purpose of the application.
I have already established a connection with OAuth to Office365, using OAuth.
I cannot figure out the smallest subset of permissions I need. I have not found any documentation regarding this. Any subset of rights I tried, I get a 401 when I ask for WorkHours.
Minimal Code sample
This will work when I enable 38 non-admin permissions that the app registration for Exchange Online supports, but will fail for every subset I have tried.
[TestMethod]
public void ConnectUsingEws()
{
var accessToken = "eyJz93a...k4laUWw";
var credentials = new OAuthCredentials(accessToken);
var service = new ExchangeService(TimeZoneInfo.Utc);
service.Url = new Uri("https://outlook.office365.com/EWS/exchange.asmx");
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.Credentials = credentials;
// This next line is where the service will always throw a 401.
var workHours = UserConfiguration.Bind(service, "WorkHours",
WellKnownFolderName.Calendar, UserConfigurationProperties.All);
// Do some XML magic on workHours to get the timezone.
}
TLDR
I'm sure it's one permission that needs to be enabled, and I'm also fairly certain it's not one that's very obvious.
EWS doesn't support the same level of Permission scopes that REST does with Oauth (which is a big downside of using EWS for a security perspective).
OAuth authentication for EWS is only available in Exchange as part of
Office 365. EWS applications require the "Full access to user's
mailbox" permission.
ref https://msdn.microsoft.com/en-us/library/office/dn903761(v=exchg.150).aspx

403 when connecting to Exchange Online

I am trying to use EWS on an Office 365 account however I get a return of (403 Forbidden)
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = new WebCredentials("mv003237", "correctpw","domain");
service.AutodiscoverUrl("mv003237#domain.co.uk");
To login and view the Webservices file on outlook.com/EWS/Exchange.asmx I need to authenticate with mv003237#live.domain.co.uk
I have tried several combinations of this and still get the same error message.
Has anyone had a similar experience of connecting to an office 365 account before?
My WINDOWS login for this account does have a domain of RDG-HOME but I haven't seen a domain for login into OWA.
Many thanks in advance
If you've already removed the domain name (as Matt suggested in his comment) the one thing that remains is to automatically follow redirects in the autodiscover process.
Change your last line to
service.AutodiscoverUrl("mv003237#domain.co.uk", redirect => true);
to follow the redirection response that Exchange Online sends.
So the complete sequence then becomes:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = new WebCredentials("mv003237", "correctpw");
service.AutodiscoverUrl("mv003237#domain.co.uk", redirect => true);
Cannot comment due to low reputation score and hence responding as an answer.
Are you able to login into OWA with "mv003237#domain.co.uk"? If yes, have you tried by hardcoding Url instead of using Autodiscover to understand if issue is with Autodiscover or EWS. Try following instead of autodiscover call:
service.Url = new Uri(#"https://outlook.office365.com/ews/exchange.asmx");
If above works fine, subscribe to RedirectionUrlValidationCallback with AutodiscoverService and see which redirected URL is throwing 403. Or enable verbose logging with Trace* properties present on service object.

UseDefaultCredentials with Exchange Web Services

I'm a pretty new programmer. One of the things I've been tasked with at work is getting our custom tools to create draft emails and drop them into the draft email folder of the user running the tool. We presently use Exchange Server 2010 (but are in the process of migrating over to Exchange Online).
This link talks about a UseDefaultCredentials but I can't seem to work out how to implement it. I created an ExchangeService object called service and managed to interact with our Exchange server using this for credentials:
service.Credentials = new WebCredentials("my login name", "my password");
I'd like to be able to eliminate that from the code and have it use the credentials of the logged-in user who is using the tool. Is that possible?
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);
service.Credentials = new WebCredentials(CredentialCache.DefaultNetworkCredentials);
if you use the defaultcredentials you can eliminate your posted code. Just set "UseDefaultCredentials" to True and don't set the Credentials manually. In this case the credentials of the User who is running your tool will be taken. I use that on my own and it works finde for me.
Greets, J

Unable to connect to my Tfs server from c# code

We're trying to authenticate to our hosted TFS service account in c# using TeamFoundationServer .net control, here is my code :
NetworkCredential tfsCredential = new NetworkCredential(username, password);
TeamFoundationServer tfsServer = new TeamFoundationServer(tfsAddress, tfsCredential);
tfsServer.Authenticate();
Note that this is not an on-premises TFS server, it is the hosted TFS service at tfspreview.com and we try to sign-in with windows live account and with alternate authentication credentials but every time we try to authenticate, internet explorer open in a new windows and ask for credentials.
If we use the IE prompt to connect it works but we want to store the credentials and connect to the server without asking for the credentials every time,
You can either configure basic authentication under your profile or you can use a service credential. It all depends on what sort of permission you need. The basic auth operates under a user account which tends to be bad practice while the service account had elevated permissions.
Configure basic authentication for TF Service
For basic user authentication you should connect to TF Service and open your profile as indicated. There is a "Credentials" tab on your profile which will let you configure those credentials. This is good for per/user access through the API but is not good if you want to run things through a server or service.
Retrieve TFS Service Credentials
I created an application called the TFS Service Credential Viewer that allows you to retrieve the service credentials for your TF Service instance. This is the same thing that the Build & Test servers do when you configure them locally to work against the cloud.
I hope this helps...
You can try with this code based on impersonation of server
var serverUrl = "";
ICredentials credentials = new NetworkCredential(username, password, domain);
ICredentialsProvider TFSProxyCredentials = new NetworkCredentialsProvider(credentials);
TfsTeamProjectCollection currentCollection = new TfsTeamProjectCollection(new Uri(serverUrl), credentials);
// Get the TFS Identity Management Service
IIdentityManagementService identityManagementService = currentCollection.GetService<IIdentityManagementService>();
// Look up the user that we want to impersonate
TeamFoundationIdentity identity = identityManagementService.ReadIdentity(IdentitySearchFactor.AccountName, username, MembershipQuery.None, ReadIdentityOptions.None);
// Open collection impersonated
TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri(serverUrl), credentials, TFSProxyCredentials, identity.Descriptor);
//For example we can access to service WorkItemStore
var workItemStore = tfs.GetService<WorkItemStore>();
Tfspreview.com now supports basic authentication which would eliminate IE being displayed at all. See here for details on how to set this up for your tfspreview.com and then use the username and password you configured.

WCF windows authentication security error

i have some code that tries impersonate the callers windows security settings and then connect to another WCF service on a different machine
WindowsIdentity callerWindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;
using (callerWindowsIdentity.Impersonate())
{
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
EndpointAddress endpoint = new EndpointAddress(new Uri("net.tcp://serverName:9990/TestService1"));
ChannelFactory<WCFTest.ConsoleHost.IService1> channel = new ChannelFactory<WCFTest.ConsoleHost.IService1>(binding, endpoint);
WCFTest.ConsoleHost.IService1 service = channel.CreateChannel();
return service.PrintMessage(msg);
}
But I get the error:
"the caller was not authenticated by the service"
System.ServiceModel .... The request for security token could not be satisfied because authentication failed ...
The credentials I am trying to impersonate are valide windows credential for the box the service is on.
Any ideas why?
In order to support your scenario, you need to have an understanding of how Protocol Transition and Constrained Delegation work. You will need to configure both Active Directory and your WCF service endpoint(s) to support this. Note the use of the Service Principal Name (SPN). Take a look at the following link and see if they help you. The article has a sample to demonstrate the complete end-to-end configuration required to make this work.
How To: Impersonate the Original Caller in WCF Calling from a Web Application
Agree with marc_s this is the double-hop problem.
You need to get the windows authentication all the way through, therefore:
The request must be made in the context of a windows users
IIS must be configured to use windows authentication
Web.config must be set up for windows authentication with impersonate = true
The user that your application pool is running as, must be allowed to impersonate a user. This is the usual place where the double-hop problem occurs.
There is a right called "Impersonate a client after authentication"
http://blogs.technet.com/askperf/archive/2007/10/16/wmi-troubleshooting-impersonation-rights.aspx
Impersonation from you service to the next is a tricky issue, known as "double-hop" issue.
I don't have a final answer for that (I typically avoid it by using an explicit service account for the service that needs to call another service).
BUT: you should definitely check out the WCF Security Guidance on CodePlex and search for "Impersonation" - there are quite a few articles there that explain all the ins and outs of impersonating an original caller and why it's tricky.
Marc
If you are sure you have the credentials right on both hops, the next thing that could be causing the issue is the lack of the EndpointDnsIdentity being set on the endpoint.
DnsEndpointIdentity identity = new DnsEndpointIdentity("localhost"); // localhost is default. Change if your service uses a different value in the service's config.
Uri uri = new Uri("net.tcp://serverName:9990/TestService1");
endpoint = new EndpointAddress(uri, identity, new AddressHeaderCollection());

Categories

Resources