/* Copyright (c) Citrix Systems Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.IO; using System.Net; using System.Runtime.Serialization; using XenAPI; using System.Web.Script.Serialization; namespace XenAdmin.Actions { public class HealthCheckAuthenticationAction : AsyncAction { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private readonly string username; private readonly string password; private readonly long tokenExpiration; private string uploadToken; private string diagnosticToken; private const string identityTokenUrl = "/auth/api/create_identity/"; private const string uploadGrantTokenUrl = "/feeds/api/create_grant/"; private const string uploadTokenUrl = "/feeds/api/create_upload/"; private const string diagnosticTokenUrl = "/diag_sdk/token_grant/"; private readonly string identityTokenDomainName = "https://cis.citrix.com"; private readonly string uploadGrantTokenDomainName = "https://rttf.citrix.com"; private readonly string uploadTokenDomainName = "https://rttf.citrix.com"; private readonly string diagnosticTokenDomainName = " https://cis.citrix.com"; private readonly string productKey = "1a2d94a4263cd016dd7a7d510bde87f058a0b75d"; public HealthCheckAuthenticationAction(string username, string password, long tokenExpiration, bool suppressHistory) : base(null, Messages.ACTION_HEALTHCHECK_AUTHENTICATION, Messages.ACTION_HEALTHCHECK_AUTHENTICATION_PROGRESS, suppressHistory) { this.username = username; this.password = password; this.tokenExpiration = tokenExpiration; } public HealthCheckAuthenticationAction(string username, string password, string identityTokenDomainName, string uploadGrantTokenDomainName, string uploadTokenDomainName, string diagnosticTokenDomainName, string productKey, long tokenExpiration, bool suppressHistory) : this(username, password, tokenExpiration, suppressHistory) { if (!string.IsNullOrEmpty(identityTokenDomainName)) this.identityTokenDomainName = identityTokenDomainName; if (!string.IsNullOrEmpty(uploadGrantTokenDomainName)) this.uploadGrantTokenDomainName = uploadGrantTokenDomainName; if (!string.IsNullOrEmpty(uploadTokenDomainName)) this.uploadTokenDomainName = uploadTokenDomainName; if (!string.IsNullOrEmpty(diagnosticTokenDomainName)) this.diagnosticTokenDomainName = diagnosticTokenDomainName; if (!string.IsNullOrEmpty(productKey)) this.productKey = productKey; } protected override void Run() { try { string identityToken = GetIdentityToken(); string uploadGrantToken = GetUploadGrantToken(identityToken); uploadToken = GetUploadToken(uploadGrantToken); diagnosticToken = GetDiagnosticToken(identityToken); } catch (HealthCheckAuthenticationException) { throw; } catch (Exception e) { throw new HealthCheckAuthenticationException(e); } } public string UploadToken { get { return uploadToken; } } public string DiagnosticToken { get { return diagnosticToken; } } private string GetIdentityToken() { var json = new JavaScriptSerializer().Serialize(new { username, password }); var urlString = string.Format("{0}{1}", identityTokenDomainName, identityTokenUrl); try { return GetToken(urlString, json, null); } catch (WebException e) { log.InfoFormat("WebException while getting identity token from {0}. Exception Message: {1} ", identityTokenDomainName, e.Message); if (e.Status == WebExceptionStatus.ProtocolError && ((HttpWebResponse) e.Response).StatusCode == HttpStatusCode.Forbidden) throw new HealthCheckAuthenticationException(Messages.HEALTH_CHECK_AUTHENTICATION_INVALID_CREDENTIALS, e); throw; } catch (Exception e) { log.InfoFormat("Exception while getting identity token from {0}. Exception Message: {1} ", identityTokenDomainName, e.Message); throw; } } private string GetUploadGrantToken(string identityToken) { var json = new JavaScriptSerializer().Serialize(new { identity_token = identityToken }); if (tokenExpiration != 0) { json = new JavaScriptSerializer().Serialize(new { identity_token = identityToken, expiration = tokenExpiration }); } var urlString = string.Format("{0}{1}", uploadGrantTokenDomainName, uploadGrantTokenUrl); try { return GetToken(urlString, json, null); } catch (Exception e) { log.InfoFormat("Exception while getting upload grant token from {0}. Exception Message: {1} ", uploadGrantTokenDomainName, e.Message); throw; } } private string GetUploadToken(string grantToken) { var json = new JavaScriptSerializer().Serialize(new { grant_token = grantToken, product_key = productKey, expiration = tokenExpiration }); var urlString = string.Format("{0}{1}", uploadTokenDomainName, uploadTokenUrl); try { return GetToken(urlString, json, null); } catch (Exception e) { log.InfoFormat("Exception while getting upload token from {0}. Exception Message: {1} ", uploadTokenDomainName, e.Message); throw; } } private string GetDiagnosticToken(string identityToken) { var json = new JavaScriptSerializer().Serialize(new { agent = "XenServer", max_age = tokenExpiration }); var urlString = string.Format("{0}{1}", diagnosticTokenDomainName, diagnosticTokenUrl); try { return GetToken(urlString, json, "BT " + identityToken); } catch (Exception e) { log.InfoFormat("Exception while getting diagnostic token from {0}. Exception Message: {1} ", diagnosticTokenDomainName, e.Message); throw; } } private string GetToken(string urlString, string jsonParameters, string authorizationHeader) { var httpWebRequest = (HttpWebRequest) WebRequest.Create(urlString); if (authorizationHeader != null) { httpWebRequest.Headers.Add("Authorization", authorizationHeader); } httpWebRequest.ContentType = "application/json"; httpWebRequest.Method = "POST"; using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { streamWriter.Write(jsonParameters); } string result; var httpResponse = (HttpWebResponse) httpWebRequest.GetResponse(); using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) { result = streamReader.ReadToEnd(); } TemplateResponse response = new JavaScriptSerializer().Deserialize(result); return response.Token; } class TemplateResponse { public string Token { get; set; } } [Serializable] public class HealthCheckAuthenticationException : Exception { public HealthCheckAuthenticationException() : base() { } public HealthCheckAuthenticationException(string message) : base(message) { } public HealthCheckAuthenticationException(string message, Exception exception) : base(message, exception) { } public HealthCheckAuthenticationException(Exception exception) : base(Messages.HEALTH_CHECK_AUTHENTICATION_FAILED, exception) { } public HealthCheckAuthenticationException(SerializationInfo serialinfo, StreamingContext context) : base(serialinfo, context) { } } } }