private Dictionary <string, string> CheckServiceLicense() { // check request validity (unless it's for the @config uri, which is a special case) Dictionary <string, string> result = null; if ((Feature.Service.Self != null) && (Feature.Service is IDreamServiceLicense) && !(Uri.LastSegment ?? string.Empty).EqualsInvariant("@config")) { string service_license = ((IDreamServiceLicense)Feature.Service).ServiceLicense; if (string.IsNullOrEmpty(service_license)) { throw new DreamAbortException(DreamMessage.LicenseRequired("service-license missing")); } // extract public RSA key for validation RSACryptoServiceProvider public_key = RSAUtil.ProviderFrom(Feature.Service.GetType().Assembly); if (public_key == null) { throw new DreamAbortException(DreamMessage.InternalError("service assembly invalid")); } // validate the service-license try { // parse service-license result = HttpUtil.ParseNameValuePairs(service_license); if (!Encoding.UTF8.GetBytes(service_license.Substring(0, service_license.LastIndexOf(','))).VerifySignature(result["dsig"], public_key)) { throw new DreamAbortException(DreamMessage.InternalError("invalid service-license")); } } catch (Exception e) { // unexpected error, blame it on the license if (e is DreamAbortException) { throw; } else { throw new DreamAbortException(DreamMessage.InternalError("corrupt service-license")); } } // check license string text; if ((!result.TryGetValue("licensee", out text) || string.IsNullOrEmpty(text)) && !result.ContainsKey("expire")) { // unexpected error, blame it on the license throw new DreamAbortException(DreamMessage.InternalError("corrupt service-license")); } // determine 'now' date-time DateTime now = GlobalClock.UtcNow; DateTime?request_date = Request.Headers.Date; if (request_date.HasValue) { now = (request_date.Value > now) ? request_date.Value : now; } // check expiration DateTime expire; if (result.TryGetValue("expire", out text) && (!DateTimeUtil.TryParseInvariant(text, out expire) || (expire.ToUniversalTime() < now))) { throw new DreamAbortException(DreamMessage.LicenseRequired("service-license has expired")); } } return(result); }
/// <summary> /// Perform startup configuration of a service instance. /// </summary> /// <remarks> /// Should not be manually invoked and should only be overridden if <see cref="Start(MindTouch.Xml.XDoc,Autofac.ILifetimeScope,MindTouch.Tasking.Result)"/> isn't already overriden. /// </remarks> /// <param name="config">Service configuration.</param> /// <param name="result">Synchronization handle for coroutine invocation.</param> /// <returns>Iterator used by <see cref="Coroutine"/> execution environment.</returns> protected virtual Yield Start(XDoc config, Result result) { Result <DreamMessage> res; // store configuration and uri _config = config; _self = Plug.New(config["uri.self"].AsUri); if (_self == null) { throw new ArgumentNullException("config", "Missing element'uri.self'"); } _owner = Plug.New(config["uri.owner"].AsUri); // check for service access keys var internalAccessKey = config["internal-service-key"].AsText; if (!string.IsNullOrEmpty(internalAccessKey)) { _internalAccessKey = internalAccessKey; } var privateAccessKey = config["private-service-key"].AsText; if (!string.IsNullOrEmpty(privateAccessKey)) { _privateAccessKey = privateAccessKey; } // check for api-key settings _apikey = config["apikey"].AsText; // process 'set-cookie' entries var setCookies = DreamCookie.ParseAllSetCookieNodes(config["set-cookie"]); if (setCookies.Count > 0) { Cookies.Update(setCookies, null); } // grant private access key to self, host, and owner var privateAcccessCookie = DreamCookie.NewSetCookie("service-key", PrivateAccessKey, Self.Uri); Cookies.Update(privateAcccessCookie, null); yield return(Env.At("@grants").Post(DreamMessage.Ok(privateAcccessCookie.AsSetCookieDocument), new Result <DreamMessage>(TimeSpan.MaxValue))); if (Owner != null) { yield return(res = Owner.At("@grants").Post(DreamMessage.Ok(privateAcccessCookie.AsSetCookieDocument), new Result <DreamMessage>(TimeSpan.MaxValue))); if (!res.Value.IsSuccessful) { throw new ArgumentException("unexpected failure setting grants on owner service"); } } // check if this service requires a service-license to work if (this is IDreamServiceLicense) { string service_license = config["service-license"].AsText; if (string.IsNullOrEmpty(service_license)) { throw new DreamAbortException(DreamMessage.LicenseRequired("service-license missing")); } // extract public RSA key for validation RSACryptoServiceProvider public_key = RSAUtil.ProviderFrom(GetType().Assembly); if (public_key == null) { throw new DreamAbortException(DreamMessage.InternalError("service assembly invalid")); } // validate the service-license _license = null; Dictionary <string, string> values; try { // parse service-license values = HttpUtil.ParseNameValuePairs(service_license); if (!Encoding.UTF8.GetBytes(service_license.Substring(0, service_license.LastIndexOf(','))).VerifySignature(values["dsig"], public_key)) { throw new DreamAbortException(DreamMessage.InternalError("invalid service-license (1)")); } // check if the SID matches string sid; if (!values.TryGetValue("sid", out sid) || !SID.HasPrefix(XUri.TryParse(sid), true)) { throw new DreamAbortException(DreamMessage.InternalError("invalid service-license (2)")); } _license = service_license; } catch (Exception e) { // unexpected error, blame it on the license if (e is DreamAbortException) { throw; } throw new DreamAbortException(DreamMessage.InternalError("corrupt service-license (1)")); } // validate expiration date string expirationtext; if (values.TryGetValue("expire", out expirationtext)) { try { DateTime expiration = DateTime.Parse(expirationtext); if (expiration < DateTime.UtcNow) { _license = null; } } catch (Exception e) { _license = null; // unexpected error, blame it on the license if (e is DreamAbortException) { throw; } throw new DreamAbortException(DreamMessage.InternalError("corrupt service-license (2)")); } } // check if a license was assigned if (_license == null) { throw new DreamAbortException(DreamMessage.LicenseRequired("service-license has expired")); } } else { config["service-license"].RemoveAll(); } // create built-in services _storage = Plug.New(config["uri.storage"].AsUri); _pubsub = Plug.New(config["uri.pubsub"].AsUri); // done _log.Debug("Start"); result.Return(); }