Created
August 12, 2014 19:03
-
-
Save sharwell/f79e5aa52c8ad7d32af1 to your computer and use it in GitHub Desktop.
SoftLayer Identity Provider Example (WIP)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace net.openstack.Providers.SoftLayer | |
{ | |
using System; | |
using System.Linq; | |
using net.openstack.Core.Caching; | |
using net.openstack.Core.Domain; | |
using net.openstack.Core.Providers; | |
using net.openstack.Providers.Rackspace; | |
using Newtonsoft.Json; | |
using Newtonsoft.Json.Linq; | |
using HttpMethod = JSIStudios.SimpleRESTServices.Client.HttpMethod; | |
using IRestService = JSIStudios.SimpleRESTServices.Client.IRestService; | |
using JsonRestServices = JSIStudios.SimpleRESTServices.Client.Json.JsonRestServices; | |
/// <summary> | |
/// Provides an implementation of <see cref="IIdentityProvider"/> for operating with | |
/// SoftLayer's authentication service. | |
/// </summary> | |
/// <threadsafety/> | |
/// <preliminary/> | |
public class SoftLayerIdentityProvider : CloudIdentityProvider | |
{ | |
private static string UserAccessTemplate = | |
"{\n" + | |
" \"token\": {\n" + | |
" \"expires\": \"{ExpirationDate}\",\n" + | |
" \"id\": \"{X-Auth-Token}\",\n" + | |
" \"tenant\": {\n" + | |
" \"id\": \"{TenantId}\",\n" + | |
" \"name\": \"{TenantId}\"\n" + | |
" }\n" + | |
" },\n" + | |
" \"user\": {\n" + | |
" \"id\": \"{UserId}\",\n" + | |
" \"name\": \"{UserName}\",\n" + | |
" \"roles\": [],\n" + | |
" \"RAX-AUTH:defaultRegion\": \"NoRegion\"\n" + | |
" },\n" + | |
" \"serviceCatalog\": [\n" + | |
" {\n" + | |
" \"name\": \"cloudFiles\",\n" + | |
" \"type\": \"object-store\",\n" + | |
" \"endpoints\": [\n" + | |
" {\n" + | |
" \"publicURL\": \"{X-Storage-Url}\",\n" + | |
" \"region\": \"NoRegion\"\n" + | |
" }\n" + | |
" ]\n" + | |
" }\n" + | |
" ]\n" + | |
"}\n"; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="SoftLayerIdentityProvider"/> class | |
/// with no default identity, the specified base URL, and the default REST service | |
/// implementation and token cache. | |
/// </summary> | |
/// <param name="urlBase">The base URL for the cloud instance.</param> | |
/// <exception cref="ArgumentNullException">If <paramref name="urlBase"/> is <see langword="null"/>.</exception> | |
public SoftLayerIdentityProvider(Uri urlBase) | |
: this(urlBase, null, null, null) | |
{ | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="SoftLayerIdentityProvider"/> class | |
/// with the specified default identity and base URL, and the default REST service | |
/// implementation and token cache. | |
/// </summary> | |
/// <param name="urlBase">The base URL for the cloud instance.</param> | |
/// <param name="defaultIdentity">The default identity to use for calls that do not explicitly specify an identity. If this value is <see langword="null"/>, no default identity is available so all calls must specify an explicit identity.</param> | |
/// <exception cref="ArgumentNullException">If <paramref name="urlBase"/> is <see langword="null"/>.</exception> | |
public SoftLayerIdentityProvider(Uri urlBase, CloudIdentity defaultIdentity) | |
: this(urlBase, defaultIdentity, null, null) | |
{ | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="SoftLayerIdentityProvider"/> class | |
/// with no default identity, and the specified base URL, REST service | |
/// implementation, and token cache. | |
/// </summary> | |
/// <param name="urlBase">The base URL for the cloud instance.</param> | |
/// <param name="restService">The implementation of <see cref="IRestService"/> to use for executing REST requests. If this value is <see langword="null"/>, the provider will use a new instance of <see cref="JsonRestServices"/>.</param> | |
/// <param name="tokenCache">The cache to use for caching user access tokens. If this value is <see langword="null"/>, the provider will use <see cref="UserAccessCache.Instance"/>.</param> | |
/// <exception cref="ArgumentNullException">If <paramref name="urlBase"/> is <see langword="null"/>.</exception> | |
public SoftLayerIdentityProvider(Uri urlBase, IRestService restService, ICache<UserAccess> tokenCache) | |
: this(urlBase, null, restService, tokenCache) | |
{ | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="SoftLayerIdentityProvider"/> class | |
/// using the provided values. | |
/// </summary> | |
/// <param name="urlBase">The base URL for the cloud instance.</param> | |
/// <param name="defaultIdentity">The default identity to use for calls that do not explicitly specify an identity. If this value is <see langword="null"/>, no default identity is available so all calls must specify an explicit identity.</param> | |
/// <param name="restService">The implementation of <see cref="IRestService"/> to use for executing REST requests. If this value is <see langword="null"/>, the provider will use a new instance of <see cref="JsonRestServices"/>.</param> | |
/// <param name="tokenCache">The cache to use for caching user access tokens. If this value is <see langword="null"/>, the provider will use <see cref="UserAccessCache.Instance"/>.</param> | |
/// <exception cref="ArgumentNullException">If <paramref name="urlBase"/> is <see langword="null"/>.</exception> | |
public SoftLayerIdentityProvider(Uri urlBase, CloudIdentity defaultIdentity, IRestService restService, ICache<UserAccess> tokenCache) | |
: base(defaultIdentity, restService, tokenCache, urlBase) | |
{ | |
if (urlBase == null) | |
throw new ArgumentNullException("urlBase"); | |
} | |
private static string GenerateUserAccess(DateTimeOffset expirationDate, string authToken, string tenantId, string userId, string userName, string storageUrl) | |
{ | |
return UserAccessTemplate | |
.Replace("{ExpirationDate}", JsonConvert.SerializeObject(expirationDate).Trim('"')) | |
.Replace("{X-Auth-Token}", authToken) | |
.Replace("{TenantId}", tenantId) | |
.Replace("{UserId}", userId) | |
.Replace("{UserName}", userName) | |
.Replace("{X-Storage-Url}", storageUrl); | |
} | |
/// <inheritdoc/> | |
public override UserAccess GetUserAccess(CloudIdentity identity, bool forceCacheRefresh = false) | |
{ | |
Func<UserAccess> refreshCallback = | |
() => | |
{ | |
// TODO: prepare and the authentication request to obtain the placeholders | |
JObject requestBody = null; | |
var response = ExecuteRESTRequest<JObject>(identity, new Uri(UrlBase, "/auth/v1.0"), HttpMethod.POST, requestBody, isTokenRequest: true); | |
if (response == null || response.Data == null) | |
return null; | |
DateTimeOffset expirationDate = DateTimeOffset.Now; | |
string authToken = response.Headers.First(i => i.Key.Equals("X-Auth-Token", StringComparison.OrdinalIgnoreCase)).Value; | |
string tenantId = identity.Username; | |
string userId = identity.Username; | |
string userName = identity.Username; | |
string storageUrl = response.Headers.First(i => i.Key.Equals("X-Storage-Url", StringComparison.OrdinalIgnoreCase)).Value; | |
UserAccess access = JsonConvert.DeserializeObject<UserAccess>(GenerateUserAccess(expirationDate, authToken, tenantId, userId, userName, storageUrl)); | |
if (access == null || access.Token == null) | |
return null; | |
return access; | |
}; | |
string key = string.Format("{0}:{1}/{2}/{3}", UrlBase, identity.Username, identity.APIKey, identity.Password); | |
var userAccess = TokenCache.Get(key, refreshCallback, forceCacheRefresh); | |
return userAccess; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment