Skip to content
This repository has been archived by the owner on Jan 19, 2024. It is now read-only.

Commit

Permalink
TSE Feature Support
Browse files Browse the repository at this point in the history
- Added support for TSE
- Removed Security Token in URL
- Added User Agent
  • Loading branch information
sfdrogojan authored and manivinesh committed Nov 19, 2018
1 parent dc60c90 commit 6b4c2f4
Show file tree
Hide file tree
Showing 33 changed files with 676 additions and 52 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,4 @@ FuelSDK-CSharp/fixer.awk
*.suo
FuelSDK-CSharp.v12.suo
FuelSDK-Test/App.config
/.vs/
32 changes: 32 additions & 0 deletions FuelSDK-CSharp/AuthEndpointUriBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;

namespace FuelSDK
{
public class AuthEndpointUriBuilder
{
private const string legacyQuery = "legacy=1";
private readonly FuelSDKConfigurationSection configSection;

public AuthEndpointUriBuilder(FuelSDKConfigurationSection configSection)
{
this.configSection = configSection;
}

public string Build()
{
UriBuilder uriBuilder = new UriBuilder(configSection.AuthenticationEndPoint);

if (uriBuilder.Query.ToLower().Contains(legacyQuery))
{
return uriBuilder.Uri.AbsoluteUri;
}

if (uriBuilder.Query.Length > 1)
uriBuilder.Query = uriBuilder.Query.Substring(1) + "&" + legacyQuery;
else
uriBuilder.Query = legacyQuery;

return uriBuilder.Uri.AbsoluteUri;
}
}
}
12 changes: 12 additions & 0 deletions FuelSDK-CSharp/ConfigUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Configuration;

namespace FuelSDK
{
class ConfigUtil
{
public static FuelSDKConfigurationSection GetFuelSDKConfigSection()
{
return (FuelSDKConfigurationSection)ConfigurationManager.GetSection("fuelSDK");
}
}
}
23 changes: 23 additions & 0 deletions FuelSDK-CSharp/DefaultEndpoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace FuelSDK
{
/// <summary>
/// Contains the default endpoints for the SDK.
/// </summary>
public static class DefaultEndpoints
{
/// <summary>
/// The default SOAP endpoint
/// </summary>
public static string Soap => "https://webservice.s4.exacttarget.com/Service.asmx";

This comment has been minimized.

Copy link
@TobiasBengtsson

TobiasBengtsson Feb 26, 2019

Why is this hard-coded to the s4 stack?


/// <summary>
/// The default authentication endpoint
/// </summary>
public static string Auth => "https://auth.exacttargetapis.com/v1/requestToken?legacy=1";

/// <summary>
/// The default REST endpoint
/// </summary>
public static string Rest => "https://www.exacttargetapis.com";
}
}
2 changes: 1 addition & 1 deletion FuelSDK-CSharp/ETCampaign.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class ETCampaign : FuelObject
/// </summary>
public ETCampaign()
{
Endpoint = "https://www.exacttargetapis.com/hub/v1/campaigns/{ID}";
Endpoint = ConfigUtil.GetFuelSDKConfigSection().RestEndPoint + "/hub/v1/campaigns/{ID}";
URLProperties = new[] { "ID" };
RequiredURLProperties = new string[0];
}
Expand Down
2 changes: 1 addition & 1 deletion FuelSDK-CSharp/ETCampaignAsset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class ETCampaignAsset : FuelObject
/// </summary>
public ETCampaignAsset()
{
Endpoint = "https://www.exacttargetapis.com/hub/v1/campaigns/{CampaignID}/assets/{ID}";
Endpoint = ConfigUtil.GetFuelSDKConfigSection().RestEndPoint + "/hub/v1/campaigns/{CampaignID}/assets/{ID}";
URLProperties = new[] { "CampaignID", "ID" };
RequiredURLProperties = new[] { "CampaignID" };
}
Expand Down
77 changes: 54 additions & 23 deletions FuelSDK-CSharp/ETClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.XPath;
using JWT;
using JWT.Serializers;
using Newtonsoft.Json.Linq;
Expand All @@ -23,7 +20,8 @@ namespace FuelSDK
/// </summary>
public class ETClient
{
public const string SDKVersion = "FuelSDX-C#-v1.0.0";
public const string SDKVersion = "FuelSDK-C#-v1.1.0";

private FuelSDKConfigurationSection configSection;
public string AuthToken { get; private set; }
public SoapClient SoapClient { get; private set; }
Expand All @@ -34,7 +32,12 @@ public class ETClient
public string EnterpriseId { get; private set; }
public string OrganizationId { get; private set; }
public string Stack { get; private set; }
private string authEndPoint { get; set; }

private static DateTime soapEndPointExpiration;
private static DateTime stackKeyExpiration;
private static string fetchedSoapEndpoint;
private const long cacheDurationInMinutes = 10;

public class RefreshState
{
public string RefreshKey { get; set; }
Expand All @@ -50,6 +53,9 @@ public ETClient(NameValueCollection parameters = null, RefreshState refreshState
// Get configuration file and set variables
configSection = (FuelSDKConfigurationSection)ConfigurationManager.GetSection("fuelSDK");
configSection = (configSection != null ? (FuelSDKConfigurationSection)configSection.Clone() : new FuelSDKConfigurationSection());
configSection = configSection
.WithDefaultAuthEndpoint(DefaultEndpoints.Auth)
.WithDefaultRestEndpoint(DefaultEndpoints.Rest);
if (parameters != null)
{
if (parameters.AllKeys.Contains("appSignature"))
Expand All @@ -64,6 +70,10 @@ public ETClient(NameValueCollection parameters = null, RefreshState refreshState
{
configSection.AuthenticationEndPoint = parameters["authEndPoint"];
}
if (parameters.AllKeys.Contains("restEndPoint"))
{
configSection.RestEndPoint = parameters["restEndPoint"];
}
}

if (string.IsNullOrEmpty(configSection.ClientId) || string.IsNullOrEmpty(configSection.ClientSecret))
Expand Down Expand Up @@ -105,15 +115,9 @@ public ETClient(NameValueCollection parameters = null, RefreshState refreshState
organizationFind = true;
}

// Find the appropriate endpoint for the acccount
var grSingleEndpoint = new ETEndpoint { AuthStub = this, Type = "soap" }.Get();
if (grSingleEndpoint.Status && grSingleEndpoint.Results.Length == 1)
configSection.SoapEndPoint = ((ETEndpoint)grSingleEndpoint.Results[0]).URL;
else
throw new Exception("Unable to determine stack using /platform/v1/endpoints: " + grSingleEndpoint.Message);
FetchSoapEndpoint();

// Create the SOAP binding for call with Oauth.

SoapClient = new SoapClient(GetSoapBinding(), new EndpointAddress(new Uri(configSection.SoapEndPoint)));
SoapClient.ClientCredentials.UserName.UserName = "*";
SoapClient.ClientCredentials.UserName.Password = "*";
Expand All @@ -139,11 +143,44 @@ public ETClient(NameValueCollection parameters = null, RefreshState refreshState
{
EnterpriseId = results[0].Client.EnterpriseID.ToString();
OrganizationId = results[0].ID.ToString();
Stack = GetStackFromSoapEndPoint(new Uri(configSection.SoapEndPoint));
Stack = StackKey.Instance.Get(long.Parse(EnterpriseId), this);
}
}
}

internal string FetchRestAuth()
{
var returnedRestAuthEndpoint = new ETEndpoint { AuthStub = this, Type = "restAuth" }.Get();
if (returnedRestAuthEndpoint.Status && returnedRestAuthEndpoint.Results.Length == 1)
return ((ETEndpoint)returnedRestAuthEndpoint.Results[0]).URL;
else
throw new Exception("REST auth endpoint could not be determined");
}

private void FetchSoapEndpoint()
{
if (string.IsNullOrEmpty(configSection.SoapEndPoint) || (DateTime.Now > soapEndPointExpiration && fetchedSoapEndpoint != null))
{
try
{
var grSingleEndpoint = new ETEndpoint { AuthStub = this, Type = "soap" }.Get();
if (grSingleEndpoint.Status && grSingleEndpoint.Results.Length == 1)
{
// Find the appropriate endpoint for the account
configSection.SoapEndPoint = ((ETEndpoint)grSingleEndpoint.Results[0]).URL;
fetchedSoapEndpoint = configSection.SoapEndPoint;
soapEndPointExpiration = DateTime.Now.AddMinutes(cacheDurationInMinutes);
}
else
configSection.SoapEndPoint = DefaultEndpoints.Soap;
}
catch
{
configSection.SoapEndPoint = DefaultEndpoints.Soap;
}
}
}

private string DecodeJWT(string jwt, string key)
{
IJsonSerializer serializer = new JsonNetSerializer();
Expand All @@ -156,14 +193,6 @@ private string DecodeJWT(string jwt, string key)
return json;
}

private string GetStackFromSoapEndPoint(Uri uri)
{
var parts = uri.Host.Split('.');
if (parts.Length < 2 || !parts[0].Equals("webservice", StringComparison.OrdinalIgnoreCase))
throw new Exception("not exacttarget.com");
return (parts[1] == "exacttarget" ? "s1" : parts[1].ToLower());
}

private static Binding GetSoapBinding()
{
return new CustomBinding(new BindingElementCollection
Expand Down Expand Up @@ -200,15 +229,17 @@ private static Binding GetSoapBinding()

public void RefreshToken(bool force = false)
{
// workaround to support TLS 1.2 in .NET 4.0 (source: https://blogs.perficient.com/2016/04/28/tsl-1-2-and-net-support/)
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
// RefreshToken
if (!string.IsNullOrEmpty(AuthToken) && DateTime.Now.AddSeconds(300) <= AuthTokenExpiration && !force)
return;

// Get an internalAuthToken using clientId and clientSecret
var strURL = configSection.AuthenticationEndPoint;
var authEndpoint = new AuthEndpointUriBuilder(configSection).Build();

// Build the request
var request = (HttpWebRequest)WebRequest.Create(strURL.Trim());
var request = (HttpWebRequest)WebRequest.Create(authEndpoint.Trim());
request.Method = "POST";
request.ContentType = "application/json";
request.UserAgent = SDKVersion;
Expand Down
3 changes: 2 additions & 1 deletion FuelSDK-CSharp/ETEndpoint.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Configuration;
using Newtonsoft.Json.Linq;

namespace FuelSDK
Expand All @@ -23,7 +24,7 @@ public class ETEndpoint : FuelObject
/// </summary>
public ETEndpoint()
{
Endpoint = "https://www.exacttargetapis.com/platform/v1/endpoints/{Type}";
Endpoint = ConfigUtil.GetFuelSDKConfigSection().RestEndPoint + "/platform/v1/endpoints/{Type}";
URLProperties = new[] { "Type" };
RequiredURLProperties = new string[0];
}
Expand Down
30 changes: 10 additions & 20 deletions FuelSDK-CSharp/FuelReturn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,11 +410,11 @@ protected TResult[] ExecuteAPI<TResult, TObject>(Func<APIObject, TObject> select
client.RefreshToken();
using (var scope = new OperationContextScope(client.SoapClient.InnerChannel))
{
// Add oAuth token to SOAP header.
XNamespace ns = "http://exacttarget.com";
var oauthElement = new XElement(ns + "oAuthToken", client.InternalAuthToken);
var xmlHeader = MessageHeader.CreateHeader("oAuth", "http://exacttarget.com", oauthElement);
OperationContext.Current.OutgoingMessageHeaders.Add(xmlHeader);
// Add oAuth token to SOAP header.
XNamespace ns = "http://exacttarget.com";
var oauthElement = new XElement(ns + "oAuthToken", client.InternalAuthToken);
var xmlHeader = MessageHeader.CreateHeader("oAuth", "http://exacttarget.com", oauthElement);
OperationContext.Current.OutgoingMessageHeaders.Add(xmlHeader);

var httpRequest = new System.ServiceModel.Channels.HttpRequestMessageProperty();
OperationContext.Current.OutgoingMessageProperties.Add(System.ServiceModel.Channels.HttpRequestMessageProperty.Name, httpRequest);
Expand All @@ -427,16 +427,6 @@ protected TResult[] ExecuteAPI<TResult, TObject>(Func<APIObject, TObject> select
MoreResults = (response.OverallStatus == "MoreDataAvailable");
Message = (response.OverallStatusMessage ?? string.Empty);

string r;
APIObject[] a;
var d = client.SoapClient.Retrieve(
new RetrieveRequest
{
ObjectType = "BusinessUnit",
Properties = new[] { "ID", "Name" }
}, out r, out a
);

return response.Results;
}
}
Expand Down Expand Up @@ -479,12 +469,12 @@ protected string ExecuteFuel(FuelObject obj, string[] required, string method, b
foreach (string urlProp in obj.URLProperties)
completeURL = completeURL.Replace("{" + urlProp + "}", string.Empty);

completeURL += "?access_token=" + obj.AuthStub.AuthToken;
if (obj.Page != 0)
completeURL += "&page=" + obj.Page.ToString();
if (obj.Page.HasValue && obj.Page.Value > 0)
completeURL += "?page=" + obj.Page.ToString();

var request = (HttpWebRequest)WebRequest.Create(completeURL.Trim());
request.Method = method;
var request = (HttpWebRequest)WebRequest.Create(completeURL.Trim());
request.Headers.Add("Authorization", "Bearer " + obj.AuthStub.AuthToken);
request.Method = method;
request.ContentType = "application/json";
request.UserAgent = ETClient.SDKVersion;

Expand Down
5 changes: 5 additions & 0 deletions FuelSDK-CSharp/FuelSDK-CSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AuthEndpointUriBuilder.cs" />
<Compile Include="ConfigUtil.cs" />
<Compile Include="DefaultEndpoints.cs" />
<Compile Include="ETClient.cs" />
<Compile Include="ExactTargetSOAP.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down Expand Up @@ -132,6 +135,8 @@
<Compile Include="ETCampaignAsset.cs" />
<Compile Include="ETEndpoint.cs" />
<Compile Include="ExecuteAPIResponse.cs" />
<Compile Include="StackKey.cs" />
<Compile Include="UserInfo.cs" />
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Service References\" />
Expand Down
Loading

0 comments on commit 6b4c2f4

Please sign in to comment.