Exchange Web Services Autodiscover non default link - c#

I am writing a piece of software that runs on a utility device on a customers network, but not on the domain. The autodiscover service is not available off domain the same as it is either on the domain or even on the internet. None of the ways the service works by default will find it according to the docs, but the customer's IT staff tells me, supposedly :/ , it will all work if I can access Autodiscover at the link they gave me. Is there any way to override the default approach and pass it this url to autodiscover from? Hardcoding the link to /exchange.asmx is not an option nor is adding this device to the domain.
I am reusing, and now tweaking, a tried and true piece of software that has been deployed many times, but this situation is a first.

Using the EWS Managed API you may be able to do it using the AutodiscoverService class. It has a constructor that takes the URI of the Autodiscover service as a parameter.
Your code should look something like this. Note that I disable SCP lookup as you are not on a domain. I have not actually tried this code but give it a try:
AutodiscoverService ads = new AutodiscoverService(new Uri("..."));
ads.EnableScpLookup = false;
ads.Credentials = new NetworkCredential(...);
ads.RedirectionUrlValidationCallback = delegate { return true; };
GetUserSettingsResponse grResp = ads.GetUserSettings("someemail#domain.com", UserSettingName.ExternalEwsUrl);
Uri casURI = new Uri(grResp.Settings[UserSettingName.ExternalEwsUrl].ToString());
var service = new ExchangeService()
{
Url = casURI,
Credentials = ads.Credentials,
};

Related

Generated WCF SOAP client uses current user for windows authentication instead of given credentials

I'm kind of new to the whole WCF and SOAP topic so please be kind.
I'm using a generated SOAP Client with .net6. In another project we successfully worked with the same Web Service using the old .net Framework 2.0 Web References and the same credentials.
Strange enough everything seemed to work fine at first. Until I realized, that it does not use the given credentials to authenticate. Instead it authenticates with my own domain user.
I also tried to get it to work with explicitly setting the binding with a BasicHttpBinding but I only could get the same broken logic to work or I got various authentication/protocol/security errors.
So it seems the authentication is basically working. It just doesn't use the provided credentials. So my question is: How can I configure it to work with the provided identity?
I also found out that it might have anything to do with a cached Windows token. But how can I get rid of it. How to prevent caching in the first place?
EDIT:
Specified the variable types explicitly.
string url = "http://someServer/AdministrationService.asmx";
AdministrationServiceSoapClient client = new AdministrationServiceSoapClient(
AdministrationServiceSoapClient.EndpointConfiguration.AdministrationServiceSoap,
url);
WindowsClientCredential credential = client.ClientCredentials.Windows;
credential.ClientCredential.UserName = "username";
credential.ClientCredential.Password = "password";
credential.ClientCredential.Domain = "DOMAIN";
GetServerInfoRequest getServerInfoRequest = new GetServerInfoRequest
{
// some stuff set here
};
GetServerInfoRequest getServerInfoReply = await client.GetServerInfoAsync(getServerInfoRequest);
As far as I know, BasicHttpBinding has security disabled by default, but can be added setting the BasicHttpSecurityMode to a value other than None in the constructor. It can be configured according to the instructions in BasicHttpBinding and BasicHttpBinding Constructors.
By default, setting up client credentials involves two steps: determining the type of client credential required by the service and specifying an actual client credential, as described in this document.
After waiting a day it is working. It seems that the cached credentials became invalid somehow.
Strange enough the simple service creation from above is not working anymore. Instead I have to use the following.
var client = new AdministrationServiceSoapClient(
new BasicHttpBinding()
{
Security = new BasicHttpSecurity()
{
Mode = BasicHttpSecurityMode.TransportCredentialOnly,
Message = new BasicHttpMessageSecurity()
{
ClientCredentialType = BasicHttpMessageCredentialType.UserName,
},
Transport = new HttpTransportSecurity()
{
ClientCredentialType = HttpClientCredentialType.Windows,
ProxyCredentialType = HttpProxyCredentialType.Windows,
}
},
},
new EndpointAddress(url));

How to get email signature from OWA/Outlook 365 using EWS Managed API

I have a problem accessing email signature using EWS (Exchange Web Services) Managed API in C#. So far I wrote this code in my Main method:
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
ExchangeService service = new ExchangeService
{
Credentials = new WebCredentials(mail, password)
};
service.UseDefaultCredentials = false;
service.AutodiscoverUrl(mail, RedirectionUrlValidationCallback);
//CertificateValidationCallBack and RedirectionUrlValidationCallback
//methods are declared in other place;
//I literally took them from Microsoft site
var OWAConfig = UserConfiguration.Bind(service, "OWA.UserOptions", WellKnownFolderName.Root,
UserConfigurationProperties.All);
This code works, but, as I understand, OWAConfig should contain all settings from OWA/Outlook 365 - but it doesn't. The OWAConfig variable has a property called Dictionary (as it should), which has 16 entries (eg. entry with key "ClientTypeOptInState" and value 2, entry with key "IsFocusedInboxEnabled" with value true, etc.). But as far as I can tell it doesn't have what I'm most interested in - the email signature.
How can I access email signature configured in OWA/Outlook 365 settings? Should I change the Bind method? Is "OWA.UserOptions" the right parameter? Does it not have the signature? Or maybe it does, but I just can't find it? Please help me.
With the introduction of the new https://office365itpros.com/2020/05/18/roaming-signatures-outlook-for-windows/ feature the signature does not get stored in that configuration item anymore. Currently Microsoft hasn't released an API to manage this signature data if you look at what OWA is doing with something like fiddler it calls PATCH https://outlook.office.com/ows/beta/OutlookCloudSettings/settings so it maybe a little bit of time before this becomes a production API that third parties can use.

SOAP error when connecting to NetSuite web services: "Namespace prefix ' soapenv' not defined"

I am getting the following error when connecting to a NetSuite production account, through the Suitetalk API:
I don't have problems connecting to the Sandbox account for this client. I am connecting through a C# WCF project. I don't believe the problem is with the c# project, since this code is being used in Production with many other clients.
It seems to me like the SOAP message being returned is incorrectly formatted - there seems to be a line break before the 'soapenv' element in the SOAP message. I am getting this error when creating a "get" request against the API(using passport login). This error occurs on any API call though, I did try simply logging in through the API as well.
I have double checked the login details and account information for this client and everything seems in orders. Besides, if this information is incorrect, I should be getting authentication errors - not malformed SOAP messages.
Any help will be appreciated, thanks!
It turns out that I needed to use the webservices.na3.netsuite WSDL. I was under the impression that the regular "webservices.netsuite" WSDL would direct any requests to the correct server.
So when connecting to a NetSuite account through SuiteTalk, be sure to make use of the correct WSDL and specify the correct endpoint along with your login credentials. You can check which server your account is hosted on by looking at the URL when logged into your NetSuite account.
Update
I made use of the newest 'DataCenterAwareNetSuiteService' class to dynamically get the correct data center for the current account that I am trying to connect to:
class DataCenterAwareNetSuiteService : NetSuiteService
{
private System.Uri OriginalUri;
public DataCenterAwareNetSuiteService(string account, bool doNotSetUrl)
: base()
{
OriginalUri = new System.Uri(this.Url);
if (account == null || account.Length == 0)
account = "empty";
if (!doNotSetUrl)
{
//var temp = getDataCenterUrls(account);
DataCenterUrls urls = getDataCenterUrls(account).dataCenterUrls;
Uri dataCenterUri = new Uri(urls.webservicesDomain + OriginalUri.PathAndQuery);
this.Url = dataCenterUri.ToString();
}
}
public void SetAccount(string account)
{
if (account == null || account.Length == 0)
account = "empty";
this.Url = OriginalUri.AbsoluteUri;
DataCenterUrls urls = getDataCenterUrls(account).dataCenterUrls;
Uri dataCenterUri = new Uri(urls.webservicesDomain + OriginalUri.PathAndQuery);
this.Url = dataCenterUri.ToString();
}
}
The above is called like so:
new DataCenterAwareNetSuiteService("*account number*", false);
With the latest version of NetSuite, some changes have been made to URLs. For instance, now you can have more than one SandBox URL. Because of this, the URL format has changed. The account number used when authenticating is also now different. For sandboxes the account Id is now passed up as ACCOUNTNUMBER_SANDBOXID, for example 12345678_SB1.
You can determine the URLs for the SOAP and REST services by using the datacenterurls endpoint and supplying the account # you would like to determine the URLS for.
https://rest.netsuite.com/rest/datacenterurls?account=YOUR_ACCOUNT_NUMBER
The functionality below is based on the answer from #Charl above.
I have made a couple changes below that provides the same functionality without using inheritance.
This may be a simpler implementation for a newer programmer who does not know how to use an inherited class.
var accountId = "1234567"; // Insert your account ID here
var Service = new NetSuiteService();
Service.Url = new Uri(Service.getDataCenterUrls(accountId).dataCenterUrls.webservicesDomain + new Uri(Service.Url).PathAndQuery).ToString();

Acumatica Web Services API Login

I am attempting to perform some basic integration using Acumatica's web services. Unfortunatly, I'm having problems logging in. According to their documentation, this process should look something like:
apitest.Screen context = new apitest.Screen();
context.CookieContainer = new System.Net.CookieContainer();
context.AllowAutoRedirect = true;
context.EnableDecompression = true;
context.Timeout = 1000000;
context.Url = "http://localhost/WebAPIVirtual/Soap/APITEST.asmx";
LoginResult result = context.Login("admin", "E618");
Simple enough. However, after creating and importing a WSDL file from Acumatica into Visual Studio, I found I don't have a Screen object. I do, however have a ScreenSoapClient object, which has a similar Login() method.
ScreenSoapClient context = new Acumatica.ScreenSoapClient("ScreenSoap");
LoginResult result = context.Login("username", "password");
That part works. In fact, the LoginResult give me a session ID. However, if I try to make any calls to the service, such as:
CR401000Content cr401000 = context.CR401000GetSchema();
I get an error: System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> PX.Data.PXNotLoggedInException: Error #185: You are not currently logged in.
While the version of Acumatica we're using does appear to be slightly newer, I'm unsure why the Screen() object isn't available. Consequently, if I try a bad username/password, Login() does fail (as it should). From what I can the tell, the ScreenSoapClient class is using service model details from web.config, so it's getting the endpoint address and other details there.
Is there something I'm missing or doing wrong?
As i see, you use WCF to create your service reference.
So you should enable cookies in service binding:
var binding = new BasicHttpBinding()
{
AllowCookies = true
};
var address = new EndpointAddress("http://localhost/WebAPIVirtual/Soap/APITEST.asmx");
var c = new ServiceReference1.ScreenSoapClient(binding, address);
Or, you can use old asmx web service reference (http://msdn.microsoft.com/en-us/library/bb628649.aspx).
Then everything will be same as in Acumatica`s documentation.
As noted in a comment above, I was able to make contact with a representative from Acumatica. He had me remove then recreate the service references in our project and try again. That apparently did the trick and the "Error #185: You are not currently logged in" error went away.

EWS Exchange Web service API AutodiscoverUrl exception

I get an error when I try to create an appointment:
The expected XML node type was XmlDeclaration, but the actual type is
Element.
This Exception occurs when I call AutodiscoverUrl.
I created a web service to do this.
[webMethod]
CreateAppointment()
{
var service = new ExchangeService(ExchangeVersion.Exchange2007_SP1)
{
Credentials = new WebCredentials("myAcount#gmail.com", "mypassowrd")
};
service.AutodiscoverUrl("myAcount#gmail.com");
//----------------------------------------------------------------------
var app = new Appointment(service)
{
Subject = "Meet George",
Body = "You need to meet George",
Location = "1st Floor Boardroom",
Start = DateTime.Now.AddHours(2),
End = DateTime.Now.AddHours(3),
IsReminderSet = true,
ReminderMinutesBeforeStart = 15
};
app.RequiredAttendees.Add(new Attendee("any#gmail.com"));
app.Save(SendInvitationsMode.SendToAllAndSaveCopy);
}
Some potential answers.
Passing in the wrong url or domain.
Passing in a bad email address.
Rebuilding the Windows Profile can sometimes help. (Warning: have an IT Admin do this). And it might be overkill.
A user could have an old, bad, or multiple outlook profiles set up. The email server name could be bad in the outlook profile. (See Control Panel > Mail)
Autodiscover depends on two things:
DNS entries that point from the users mail domain to the Autodiscover data on the Exchange server. Typically you would have a DNS entry with the name autodiscover.domain.com, but there's more than one way of setting this up for different versions of Exchange. If the correct DNS entry doesn't exist, auto-discovery will fail.
Autodiscover data hosted on the Exchange server (I believe it's an XML file) and accessed over HTTP. If this isn't accessible (perhaps it's behind a firewall) then auto-discovery will fail.
Check the appropriate DNS entries and autodiscover information is accessible to your client.

Categories