public static XDoc GetGroupXmlVerbose(GroupBE group, string relation) { XDoc groupXml = GetGroupXml(group, relation); ServiceBE authService = ServiceBL.GetServiceById(group.ServiceId); if (authService != null) { groupXml.Add(ServiceBL.GetServiceXml(authService, "authentication")); } groupXml.Start("users"); if (group.UserIdsList != null) { groupXml.Attr("count", group.UserIdsList.Length); } groupXml.Attr("href", DekiContext.Current.ApiUri.At("groups", group.Id.ToString(), "users")); groupXml.End(); //Permissions for the group RoleBE role = PermissionsBL.GetRoleById(group.RoleId); groupXml.Add(PermissionsBL.GetRoleXml(role, "group")); return(groupXml); }
public Yield GetServiceById(DreamContext context, DreamMessage request, Result <DreamMessage> response) { bool privateDetails = PermissionsBL.IsUserAllowed(DekiContext.Current.User, Permissions.ADMIN); //Private feature requires api-key var identifier = context.GetParam("id"); uint serviceId = 0; if (identifier.StartsWith("=")) { var serviceInfo = DekiContext.Current.Instance.RunningServices[XUri.Decode(identifier.Substring(1))]; if (serviceInfo != null) { serviceId = serviceInfo.ServiceId; } } else { if (!uint.TryParse(identifier, out serviceId)) { throw new DreamBadRequestException(string.Format("Invalid id '{0}'", identifier)); } } ServiceBE service = ServiceBL.GetServiceById(serviceId); if (service == null) { throw new ServiceNotFoundException(identifier); } response.Return(DreamMessage.Ok(ServiceBL.GetServiceXmlVerbose(DekiContext.Current.Instance, service, null, privateDetails))); yield break; }
private static ServiceBE NewServiceFromXml(XDoc serviceDoc, string SID, string description, bool?statusEnabled, bool?localInit, ServiceType?type, string uri, NameValueCollection config, NameValueCollection preferences) { ServiceBE service = new ServiceBE(); if (string.IsNullOrEmpty(SID) && (localInit ?? true)) { throw new ServiceMissingCreateSIDInvalidOperationException(); } if (type == null || type == ServiceType.UNDEFINED) { throw new ServiceMissingCreateTypeInvalidArgumentException(); } service.SID = SID ?? string.Empty; service.Description = description ?? string.Empty; service.ServiceEnabled = statusEnabled ?? true; service.ServiceLocal = localInit ?? true; service.Type = type.Value; service.Uri = uri ?? string.Empty; service.Preferences = preferences ?? new NameValueCollection(); service.Config = config ?? new NameValueCollection(); service.ServiceLastEdit = DateTime.UtcNow; return(service); }
internal Yield PostServicesId(DreamContext context, DreamMessage request, Result <DreamMessage> response) { ServiceBL.EnsureServiceAdministrationAllowed(); uint id = context.GetParam <uint>("id"); ServiceBE service = DbUtils.CurrentSession.Services_GetById(id); if (service == null) { throw new ServiceNotFoundException(id); } if (context.Verb.EqualsInvariantIgnoreCase("PUT")) { //Modify a service (only with PUT) service = ServiceBL.PostServiceFromXml(request.ToDocument(), service); response.Return(DreamMessage.Ok(ServiceBL.GetServiceXmlVerbose(DekiContext.Current.Instance, service, null))); } else { //Backward compatibility: posting an empty document restarts the service service = ServiceBL.StartService(service, true, true); if (service.ServiceEnabled && (service.Uri == null)) { throw new ServiceSettingsInvalidArgumentException(); } response.Return(DreamMessage.Ok(ServiceBL.GetServiceXmlVerbose(DekiContext.Current.Instance, service, null))); } yield break; }
public static ServiceBE UpdateService(ServiceBE service) { DbUtils.CurrentSession.Services_Delete(service.Id); uint serviceId = DbUtils.CurrentSession.Services_Insert(service); // reload the service return(DbUtils.CurrentSession.Services_GetById(serviceId)); }
public static XDoc GetServiceXml(ServiceBE service, string relation) { XDoc serviceXml = new XDoc(string.IsNullOrEmpty(relation) ? "service" : "service." + relation); serviceXml.Attr("id", service.Id); serviceXml.Attr("href", DekiContext.Current.ApiUri.At("site", "services", service.Id.ToString())); return(serviceXml); }
public static bool IsLocalAuthService(ServiceBE service) { if (service == null) { return(false); } return(service.Id == BUILT_IN_AUTH_SERVICE_ID); }
private static ServiceBE StopService(uint serviceId, ServiceBE service, ServiceStopType stopType) { if (IsLocalAuthService(serviceId)) { return(service); } DekiContext context = DekiContext.Current; bool saveBe = false; if (service != null && service.ServiceLocal) { // local services should have their uri cleared out _log.DebugFormat("stopping service '{0}'", service.SID); service.Uri = null; saveBe = true; } if (service != null && stopType == ServiceStopType.Disable) { // wipe out last error on disable service.ServiceLastStatus = null; saveBe = true; } var serviceInfo = context.Instance.RunningServices[serviceId]; if (serviceInfo == null) { if (saveBe) { service = UpdateService(service) ?? service; } // service is not registered as running, we're done here return(service); } try { context.Instance.DeregisterService(serviceId); } catch (Exception e) { // log the error, but ignore it otherwise if (service == null) { context.Instance.Log.WarnExceptionMethodCall(e, "StopService", string.Format("Unable to stop {0} service id '{1}'", serviceInfo.IsLocal ? "local" : "remote", serviceId)); } else { context.Instance.Log.WarnExceptionMethodCall(e, "StopService", string.Format("Unable to stop {0} service id '{1}' with SID '{2}'", serviceInfo.IsLocal ? "local" : "remote", serviceId, service.SID)); } } if (service != null && (stopType == ServiceStopType.Disable || saveBe)) { service.ServiceEnabled = (stopType != ServiceStopType.Disable); service = UpdateService(service) ?? service; } return(service); }
//--- Methods --- public IServiceInfo RegisterService(ServiceBE service, XUri serviceUri, bool isLocal) { var serviceInfo = new ServiceInfo(this, service.Id, serviceUri, isLocal); lock (_servicesById) { _servicesById[service.Id] = serviceInfo; _servicesByUri[serviceUri] = serviceInfo; RegisterNamespace(serviceInfo, service.Preferences["namespace"]); } return(serviceInfo); }
private IList <ServiceBE> Services_Populate(IDataReader dr) { // read all services List <ServiceBE> orderedServiceList = new List <ServiceBE>(); Dictionary <uint, ServiceBE> result = new Dictionary <uint, ServiceBE>(); ServiceBE s = null; while (dr.Read()) { s = new ServiceBE(); s._ServiceEnabled = dr.Read <byte>("service_enabled"); s._ServiceLocal = dr.Read <byte>("service_local"); s.Description = dr.Read <string>("service_description"); s.Id = dr.Read <uint>("service_id"); s.ServiceLastEdit = dr.Read <DateTime>("service_last_edit"); s.ServiceLastStatus = dr.Read <string>("service_last_status"); s.SID = dr.Read <string>("service_sid"); s.Type = dr.Read <ServiceType>("service_type"); s.Uri = dr.Read <string>("service_uri"); result.Add(s.Id, s); orderedServiceList.Add(s); } // read config key/value pairs for each service dr.NextResult(); while (dr.Read()) { uint serviceId = DbUtils.Convert.To <uint>(dr["service_id"], 0); if (serviceId != 0 && result.ContainsKey(serviceId)) { s = result[serviceId]; string config_name = DbUtils.Convert.To <string>(dr["config_name"], ""); string config_value = DbUtils.Convert.To <string>(dr["config_value"], ""); s.Config[config_name] = config_value; } } // read preference key/value pairs for each service dr.NextResult(); while (dr.Read()) { uint serviceId = DbUtils.Convert.To <uint>(dr["service_id"], 0); if (serviceId != 0 && result.ContainsKey(serviceId)) { s = result[serviceId]; string pref_name = DbUtils.Convert.To <string>(dr["pref_name"], ""); string pref_value = DbUtils.Convert.To <string>(dr["pref_value"], ""); s.Preferences[pref_name] = pref_value; } } return(orderedServiceList); }
public static void DeleteService(ServiceBE service) { if (IsLocalAuthService(service)) { throw new ServiceCannotDeleteAuthInvalidOperationException(); } service = StopService(service); DbUtils.CurrentSession.Services_Delete(service.Id); DbUtils.CurrentSession.Users_UpdateServicesToLocal(service.Id); DbUtils.CurrentSession.Groups_UpdateServicesToLocal(service.Id); }
public static ServiceBE RetrieveLocalAuthService() { //TODO (MaxM): This can be fixed by changing the service_type for the local auth service to uniquely find it. ServiceBE service = GetServiceById(BUILT_IN_AUTH_SERVICE_ID); if (!StringUtil.EqualsInvariantIgnoreCase(service.SID.Trim(), SID_FOR_LOCAL)) { throw new ServiceSIDExpectedFatalException(SID_FOR_LOCAL); } return(service); }
internal Yield PostServiceIdStop(DreamContext context, DreamMessage request, Result <DreamMessage> response) { ServiceBL.EnsureServiceAdministrationAllowed(); uint id = context.GetParam <uint>("id"); ServiceBE service = ServiceBL.StopService(id, false); if (service == null) { throw new ServiceNotFoundException(id); } response.Return(DreamMessage.Ok(ServiceBL.GetServiceXmlVerbose(DekiContext.Current.Instance, service, null))); yield break; }
private static void ValidateGroupMemberList(ServiceBE groupService, UserBE[] potentialMembers) { //Groups belonging to built-in auth service are allowed to contain users from remote services if (!ServiceBL.IsLocalAuthService(groupService)) { foreach (UserBE u in potentialMembers) { if (u.ServiceId != groupService.Id) { throw new GroupMembersRequireSameAuthInvalidOperationException(); } } } }
public static ServiceBE PostServiceFromXml(XDoc serviceDoc, ServiceBE serviceToProcess) { uint? serviceId; string SID, description, uri; bool? statusEnabled; bool? localInit; ServiceType? type; NameValueCollection config, preferences; ParseServiceXml(serviceDoc, out serviceId, out SID, out description, out statusEnabled, out localInit, out type, out uri, out config, out preferences); //new service if (serviceToProcess == null && (serviceId == null || serviceId == 0)) { //convert XML input to a service object serviceToProcess = NewServiceFromXml(serviceDoc, SID, description, statusEnabled, localInit, type, uri, config, preferences); //insert the service serviceId = DbUtils.CurrentSession.Services_Insert(serviceToProcess); // reload the service serviceToProcess = DbUtils.CurrentSession.Services_GetById(serviceId.Value); } else { //Validate logic of given xml if (ServiceBL.IsLocalAuthService(serviceToProcess)) { throw new ServiceCannotModifyBuiltInAuthInvalidOperationException(); } if (((uri ?? string.Empty) != string.Empty) && (localInit ?? false)) { throw new ServiceCannotSetLocalUriInvalidOperationException(); } //Stop the service before making any changes serviceToProcess = StopService(serviceToProcess); //convert XML input to a service object. serviceToProcess = UpdateServiceFromParsedXml(serviceToProcess, SID, description, statusEnabled, localInit, type, uri, config, preferences); //Update existing service serviceToProcess = UpdateService(serviceToProcess); } return(serviceToProcess); }
internal Yield DeleteSiteService(DreamContext context, DreamMessage request, Result <DreamMessage> response) { ServiceBL.EnsureServiceAdministrationAllowed(); uint id = context.GetParam <uint>("id"); ServiceBE service = DbUtils.CurrentSession.Services_GetById(id); if (service == null) { throw new ServiceNotFoundException(id); } ServiceBL.DeleteService(service); response.Return(DreamMessage.Ok()); yield break; }
private static ServiceBE UpdateServiceFromParsedXml(ServiceBE service, string SID, string description, bool?statusEnabled, bool?localInit, ServiceType?type, string uri, NameValueCollection config, NameValueCollection preferences) { //Modify only changed (non-null) values if (SID != null) { service.SID = SID; } if (service.Description != null) { service.Description = description; } if (statusEnabled != null) { service.ServiceEnabled = statusEnabled.Value; } if (localInit != null) { service.ServiceLocal = localInit.Value; } if (type != null && type.Value != ServiceType.UNDEFINED) { service.Type = type.Value; } if (uri != null) { service.Uri = uri; } if (config != null) { service.Config = config; } if (preferences != null) { service.Preferences = preferences; } return(service); }
public static void InsertDWService(ServiceBE service) { DataCommand cmd = MediaWikiConverterContext.Current.DWCatalog.NewQuery(String.Format("INSERT into services (service_type, service_sid, service_description, service_local, service_enabled) VALUES ('{0}', '{1}', '{2}', '{3}', '{4}'); SELECT LAST_INSERT_ID() as serviceid;", service.Type.ToString().ToLowerInvariant(), DataCommand.MakeSqlSafe(service.SID), DataCommand.MakeSqlSafe(service.Description), service._ServiceLocal, service._ServiceEnabled)); cmd.Execute(delegate(IDataReader dr) { while (dr.Read()) { service.Id = DbUtils.Convert.To <uint>(dr["serviceid"], 0); } }); foreach (String key in service.Config.Keys) { MediaWikiConverterContext.Current.DWCatalog.NewQuery(String.Format("INSERT into service_config (service_id, config_name, config_value) VALUES ('{0}', '{1}', '{2}')", service.Id, DataCommand.MakeSqlSafe(key), DataCommand.MakeSqlSafe(service.Config[key]))).Execute(); } }
public static XDoc GetServiceXmlVerbose(DekiInstance instance, ServiceBE service, string relation, bool privateDetails) { XDoc serviceXml = GetServiceXml(service, relation); serviceXml.Start("sid").Value(service.SID ?? string.Empty).End(); serviceXml.Start("uri").Value(XUri.TryParse(service.Uri)).End(); serviceXml.Start("type").Value(service.Type.ToString().ToLowerInvariant()).End(); serviceXml.Start("description").Value(service.Description ?? "").End(); serviceXml.Elem("date.modified", service.ServiceLastEdit); serviceXml.Elem("status", service.ServiceEnabled ? "enabled" : "disabled"); serviceXml.Start("local").Value(service.ServiceLocal).Attr("deprecated", true).End(); serviceXml.Elem("init", service.ServiceLocal ? "native" : "remote"); var serviceInfo = instance.RunningServices[service.Id]; if (serviceInfo != null && !string.IsNullOrEmpty(serviceInfo.Namespace)) { serviceXml.Elem("namespace", serviceInfo.Namespace); } if (privateDetails) { serviceXml.Elem("lasterror", service.ServiceLastStatus ?? ""); serviceXml.Start("config"); foreach (string key in service.Config.AllKeys) { serviceXml.Start("value").Attr("key", key).Value(service.Config[key]).End(); } serviceXml.End(); serviceXml.Start("preferences"); foreach (string key in service.Preferences.AllKeys) { serviceXml.Start("value").Attr("key", key).Value(service.Preferences[key]).End(); } serviceXml.End(); } return(serviceXml); }
public IList <PermissionBE> GetServicePermissions(ServiceBE service) { var dbContext = new DBContext(); DataSet dataSet; var permissions = new List <PermissionBE>(); var parameters = new SqlParameter[1]; parameters[0] = dbContext.CreateParameters("@serviceCode", service.Code); dataSet = dbContext.Read("GetServicePermissions", parameters); if (dataSet.Tables[0].Rows.Count > 0) { foreach (DataRow dr in dataSet.Tables[0].Rows) { if (Helper.GetBoolDB(dr["IsGroup"])) { permissions.Add(new PermissionsGroupBE() { Id = Helper.GetGuidDB(dr["PermissionID"]), Name = Helper.GetStringDB(dr["Name"]) }); } else { permissions.Add(new PermissionBE() { Id = Helper.GetGuidDB(dr["PermissionID"]), Name = Helper.GetStringDB(dr["Name"]) }); } } } return(permissions); }
internal Yield PostServices(DreamContext context, DreamMessage request, Result <DreamMessage> response) { ServiceBL.EnsureServiceAdministrationAllowed(); if (request.HasDocument && !request.ToDocument().IsEmpty) { //Add or Modify a service ServiceBE service = ServiceBL.PostServiceFromXml(request.ToDocument(), null); response.Return(DreamMessage.Ok(ServiceBL.GetServiceXmlVerbose(DekiContext.Current.Instance, service, null))); } else { //Backward compatibility: posting an empty document restarts all local services XDoc ret = new XDoc("services"); foreach (ServiceBE service in ServiceBL.RestartServices()) { ret.Add(ServiceBL.GetServiceXml(service, null)); } response.Return(DreamMessage.Ok(ret)); } yield break; }
public ServiceRepository.IServiceInfo CreateLocalService(ServiceBE service, string servicePath, XDoc config) { var deki = DekiContext.Current.Deki; Plug location = deki.InternalCreateService(servicePath, service.SID, config, new Result <Plug>()).Wait(); XUri sid = XUri.TryParse(service.SID); string license; DateTime?expiration; if (deki.TryGetServiceLicense(sid, out license, out expiration) && (expiration != null)) { lock (_serviceExpirations) { TaskTimer timer; if (_serviceExpirations.TryGetValue(service.Id, out timer)) { timer.Cancel(); } _serviceExpirations[service.Id] = TimerFactory.New(expiration.Value, _ => ServiceBL.StopService(service), null, TaskEnv.Clone()); } } return(RunningServices.RegisterService(service, location.Uri, true)); }
private static UserBE[] ProcessGroupMemberInput(GroupBE group, XDoc userList) { if (!userList.HasName("users")) { throw new GroupExpectedUserRootNodeInvalidArgumentException(); } ServiceBE service = ServiceBL.GetServiceById(group.ServiceId); if (service == null) { throw new GroupServiceNotFoundFatalException(group.ServiceId, group.Name); } //Changing members of an external group is not supported. You may modify members in the external provider instead. if (!ServiceBL.IsLocalAuthService(service)) { throw new ExternalGroupMemberInvalidOperationException(); } UserBE[] members = ReadUserListXml(userList); ValidateGroupMemberList(service, members); return(members); }
//--- Class Methods --- public static UserBE Authenticate(DreamContext context, DreamMessage request, uint serviceId, bool autoCreateExternalUser, bool allowAnon, out bool altPassword) { UserBE user = null; altPassword = false; // Case 1: username/fullname, password, provider (login window) // 1. Validate & retrieve fullname using credentials // Failed -> return null // 2. Populate user object // A. Populates user info // B. Populates group info in user object // 3. Does fullname exist? // Yes -> Update user (email, fullname, ...) // No -> Create user // 4. Update Group information // 5. return user object // // Case 2: fullname, password (http, api, ...) // 1. Lookup full name, exist? // Yes -> return user // No -> return null // // Case 3: auth-token (header auth) // 0. Valid auth token? // No -> return null // 1. Lookup user by name // Found -> return user // Else -> return null string userName = null; string password = null; UserBE userFromToken = null; ServiceBE authService = null; // Extract authtoken and impersonation authtoken from request. // AllowAnon is false when in GET/POST: users/authenticate or when ?authenticate=true. // Standard user authtokens are ignored when AllowAnon=false but impersonation tokens are accepted. bool impersonationOnly = !allowAnon; userFromToken = UserFromAuthTokenInRequest(context, impersonationOnly); if (userFromToken == null) { HttpUtil.GetAuthentication(context.Uri.ToUri(), request.Headers, out userName, out password); } // check if we need to retrieve authentication service information if (serviceId > 0) { authService = ServiceBL.GetServiceById(serviceId); if (authService == null) { throw new AuthServiceIdInvalidArgumentException(serviceId); } if (authService.Type != ServiceType.AUTH) { throw new AuthNotAnAuthServiceInvalidArgumentException(serviceId); } } // check if a username was provided if (!string.IsNullOrEmpty(userName)) { //Case 2: Given username + password if (authService == null) { //Assuming local user or existing external account user = DbUtils.CurrentSession.Users_GetByName(userName); if (user != null) { serviceId = user.ServiceId; authService = ServiceBL.GetServiceById(serviceId); } else { LoginAccessDenied(context, request, userName, null, password); } } if (authService == null) { throw new AuthServiceIdInvalidArgumentException(serviceId); } if (authService.Type != ServiceType.AUTH) { throw new AuthNotAnAuthServiceInvalidArgumentException(serviceId); } if (user == null) { //Performing auth on local account if (ServiceBL.IsLocalAuthService(authService)) { user = DbUtils.CurrentSession.Users_GetByName(userName); } else { //Performing external auth. Lookup by external user name user = DbUtils.CurrentSession.Users_GetByExternalName(userName, authService.Id); } if (user != null && user.ServiceId != authService.Id) { ServiceBE currentUsersAuthService = ServiceBL.GetServiceById(user.ServiceId); if (currentUsersAuthService != null) { throw new AuthLoginExternalUserConflictException(currentUsersAuthService.Description); } throw new LoginExternalUserUnknownConflictException(); } } //Local account in the db. if (user != null && ServiceBL.IsLocalAuthService(authService)) { //Validate password for local account or validate the apikey if (!IsValidAuthenticationForLocalUser(user, password, out altPassword)) { // try impersonation using the ApiKey if (string.IsNullOrEmpty(password) && PermissionsBL.ValidateRequestApiKey()) { DekiContext.Current.Instance.Log.InfoFormat("user '{0}' authenticated via apikey impersonation", userName); } else { LoginAccessDenied(context, request, userName, user.ID, password); } } } // User was not found in the db and not being asked to create it. if (user == null && !autoCreateExternalUser) { LoginAccessDenied(context, request, userName, null, password); } // Creating local account if apikey checks out and our authservice is local if (user == null && string.IsNullOrEmpty(password) && PermissionsBL.ValidateRequestApiKey() && ServiceBL.IsLocalAuthService(authService)) { XDoc newUserDoc = new XDoc("user") .Elem("username", userName); DreamMessage newUserResponse = DekiContext.Current.ApiPlug.At("users") .With("apikey", DreamContext.Current.GetParam("apikey", string.Empty)) .Post(newUserDoc); user = UserBL.GetUserById(newUserResponse.ToDocument()["/user/@id"].AsUInt ?? 0); if (user != null && !string.IsNullOrEmpty(password)) { user = UserBL.SetPassword(user, password, false); } } // Got an external account // Passing in the user object from db if it was found. List <GroupBE> externalGroups = null; if (!ServiceBL.IsLocalAuthService(authService)) { bool bypassAuthentication = false; string externalName; if (user == null || string.IsNullOrEmpty(user.ExternalName)) { externalName = userName; } else { externalName = user.ExternalName; } // If apikey is valid, try to bypass auth with the external provider // and only lookup user/group details. if (string.IsNullOrEmpty(password) && PermissionsBL.ValidateRequestApiKey()) { DekiContext.Current.Instance.Log.InfoFormat("user '{0}' authenticating being bypassed via apikey impersonation", userName); bypassAuthentication = true; } user = ExternalServiceSA.BuildUserFromAuthService(authService, user, userName, bypassAuthentication, externalName, password, out externalGroups); } // User was not found or did not authenticate with external provider if (user == null) { LoginAccessDenied(context, request, userName, null, password); } else { //New user creation from external provider if (user.ID == 0) { if (!autoCreateExternalUser) { LoginAccessDenied(context, request, userName, null, password); } } else { //user exists // TODO (steveb): ??? } if (user.UserActive) { user = UserBL.CreateOrUpdateUser(user); if (externalGroups != null) { UserBL.UpdateUsersGroups(user, externalGroups.ToArray()); } } } } else if (userFromToken != null) { // valid token exists that resolved to a user user = userFromToken; } else if (allowAnon) { // Anonymous user user = DbUtils.CurrentSession.Users_GetByName(DekiWikiService.ANON_USERNAME); } if (user == null) { //No credentials. Or token not provided or is invalid. LoginAccessDenied(context, request, null, null, password); } else if (!user.UserActive && !PermissionsBL.ValidateRequestApiKey()) { //If a valid api key is provided, override the disabled account flag throw new AuthUserDisabledForbiddenException(user.Name); } return(user); }
public static ServiceBE StopService(ServiceBE service) { return(StopService(service.Id, service, ServiceStopType.Disable)); }
//--- Methods --- public ServiceRepository.IServiceInfo RegisterRemoteService(ServiceBE service, XUri serviceUri) { return(RunningServices.RegisterService(service, serviceUri, false)); }
public static XDoc GetServiceXmlVerbose(DekiInstance instance, ServiceBE service, string relation) { return(GetServiceXmlVerbose(DekiContext.Current.Instance, service, relation, true)); }
//--- Class Methods --- public static void StartExtensionService(DekiContext context, ServiceBE service, ServiceRepository.IServiceInfo serviceInfo, bool forceRefresh) { // retrieve document describing the extension functions XUri uri = new XUri(service.Uri); XDoc manifest = null; DekiWikiService deki = context.Deki; var extension = serviceInfo.Extension; if (!service.ServiceLocal) { lock (deki.RemoteExtensionLibraries) { deki.RemoteExtensionLibraries.TryGetValue(uri, out manifest); } } if (manifest == null || forceRefresh) { manifest = Plug.New(uri).Get().ToDocument(); // normalize the extension XML manifest = manifest.TransformAsXml(_extensionConverterXslt); // check if document describes a valid extension: either the extension has no functions, or the functions have end-points if (manifest.HasName("extension") && ((manifest["function"].ListLength == 0) || (manifest["function/uri"].ListLength > 0))) { // add source uri for service manifest.Attr("uri", uri); // register service in extension list lock (deki.RemoteExtensionLibraries) { deki.RemoteExtensionLibraries[uri] = manifest; } } else { throw new ExtensionRemoveServiceInvalidOperationException(uri); } } extension.Manifest = manifest; // add function prefix if one is defined serviceInfo.Extension.SetPreference("namespace.custom", service.Preferences["namespace"]); string serviceNamespace = service.Preferences["namespace"] ?? manifest["namespace"].AsText; if (serviceNamespace != null) { serviceNamespace = serviceNamespace.Trim(); if (string.IsNullOrEmpty(serviceInfo.Namespace)) { // Note (arnec): Namespace from preferences is assigned at service creation. If we do not have one at this // point, it came from the extension manifest and needs to be registered as our default. Otherwise the // preference override persists as the namespace. context.Instance.RunningServices.RegisterNamespace(serviceInfo, serviceNamespace); } if (serviceNamespace.Length != 0) { if (!DekiScriptParser.IsIdentifier(serviceNamespace)) { throw new ExtensionNamespaceInvalidArgumentException(service.Preferences["namespace"] ?? manifest["namespace"].AsText); } } else { serviceNamespace = null; } } serviceNamespace = (serviceNamespace == null) ? string.Empty : (serviceNamespace + "."); // add custom library title extension.SetPreference("title.custom", service.Preferences["title"]); extension.SetPreference("label.custom", service.Preferences["label"]); extension.SetPreference("description.custom", service.Preferences["description"]); extension.SetPreference("uri.logo.custom", service.Preferences["uri.logo"]); extension.SetPreference("functions", service.Preferences["functions"]); extension.SetPreference("protected", service.Preferences["protected"]); // add each extension function bool.TryParse(service.Preferences["protected"], out extension.IsProtected); var functions = new List <ServiceRepository.ExtensionFunctionInfo>(); foreach (XDoc function in manifest["function"]) { XUri functionUri = function["uri"].AsUri; if (functionUri != null) { functions.Add(new ServiceRepository.ExtensionFunctionInfo(serviceNamespace + function["name"].Contents, functionUri)); } } extension.Functions = functions.ToArray(); }
//--- Class Methods --- public static ServiceBE StartService(ServiceBE service, bool forceRefresh, bool disableOnFailure) { // create subordinate request id for service start var dreamContext = DreamContext.Current; var requestId = dreamContext.GetState <string>(DreamHeaders.DREAM_REQUEST_ID); dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId + "-service_" + service.Id); try { var stopwatch = Stopwatch.StartNew(); service.ServiceLastStatus = string.Empty; StopService(service.Id, service, ServiceStopType.Restart); DekiContext context = DekiContext.Current; bool dirtyServiceEntity = false; XUri location; ServiceRepository.IServiceInfo serviceInfo = null; try { // check if service is local if (service.ServiceLocal) { if (string.IsNullOrEmpty(service.SID)) { throw new Exception("missing SID"); } // start service if (IsLocalAuthService(service)) { // this service is the built-in authentication provider; no need to start it location = context.Deki.Self; } else { // convert local service configuration into an xdoc XDoc config = new XDoc("config"); foreach (KeyValuePair <string, string> configEntry in ArrayUtil.AllKeyValues(service.Config)) { config.InsertValueAt(configEntry.Key, configEntry.Value); } // if no apikey was provided, create a random one so that CreateService doesn't inject the parent one if (config["apikey"].IsEmpty) { config.Elem("apikey", StringUtil.CreateAlphaNumericKey(16)); } // add information for service to callback into deki if (config["uri.deki"].IsEmpty) { config.Elem("uri.deki", context.Deki.Self); config.Elem("wikiid.deki", context.Instance.Id); // Providing master apikey to service for setups that don't use per instance keys config.Elem("apikey.deki", context.Instance.ApiKey.IfNullOrEmpty(context.Deki.MasterApiKey)); } // the service location must use the service ID and the instance ID string servicePath = string.Format("services/{0}/{1}", context.Instance.Id, service.Id); _log.DebugFormat("starting service '{0}' at path {1} w/ namespace {2}", service.SID, servicePath, service.Preferences["namespace"]); serviceInfo = context.Instance.CreateLocalService(service, servicePath, config); location = serviceInfo.ServiceUri; } // check if the service uri has changed since last invocation (happens when service is started for the first time or server GUID has changed) if (!service.Uri.EqualsInvariantIgnoreCase(location.ToString())) { dirtyServiceEntity = true; service.Uri = location.ToString(); } } else { _log.DebugFormat("registering remote service '{0}'", service.SID); if (string.IsNullOrEmpty(service.Uri)) { throw new Exception("missing URI"); } location = new XUri(service.Uri); serviceInfo = context.Instance.RegisterRemoteService(service, location); } // check if service is an Extension service if (service.Type == ServiceType.EXT) { if (service.ServiceLocal) { _log.DebugFormat("registering service '{0}' as extension", service.SID); } ExtensionBL.StartExtensionService(context, service, serviceInfo, forceRefresh); } //Successfully starting a service enables it. if (!service.ServiceEnabled) { dirtyServiceEntity = true; service.ServiceEnabled = true; } } catch (Exception e) { dirtyServiceEntity = true; DreamMessage dm = null; if (e is DreamResponseException) { dm = ((DreamResponseException)e).Response; string message = dm.HasDocument ? dm.ToDocument()[".//message"].AsText.IfNullOrEmpty(e.Message) : dm.ToText(); service.ServiceLastStatus = string.Format("unable to initialize service ({0})", message); } else { service.ServiceLastStatus = e.GetCoroutineStackTrace(); } if (serviceInfo != null) { try { context.Instance.DeregisterService(service.Id); } catch { } } // A service that fails to start becomes disabled if it's started explicitly (not during deki startup) if (disableOnFailure) { service.ServiceEnabled = false; } _log.ErrorExceptionMethodCall(e, "StartService", string.Format("Unable to start local service id '{0}' with SID '{1}' Error: '{2}'", service.Id, service.SID, service.ServiceLastStatus)); if (dm != null) { throw new ExternalServiceResponseException(dm); } else { throw; } } finally { // don't update remote services that haven't changed if (dirtyServiceEntity) { service = UpdateService(service); } } stopwatch.Stop(); _log.InfoFormat("Service '{0}' ({1}) started in {2}ms", service.Description, service.SID, stopwatch.ElapsedMilliseconds); return(service); } finally { // restore the request id dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId); } }
public uint Services_Insert(ServiceBE service) { StringBuilder query = null; if (service.Id == 0) { //new service query = new StringBuilder(@" /* Services_Insert */ insert into services (service_type, service_sid, service_uri, service_description, service_local, service_enabled, service_last_edit, service_last_status) values (?TYPE, ?SID, ?URI, ?DESC, ?LOCAL, ?ENABLED, ?TIMESTAMP, ?LASTSTATUS); "); query.AppendLine("select LAST_INSERT_ID() into @service_id;"); query.AppendLine("select LAST_INSERT_ID() as service_id;"); } else { //update existing service query = new StringBuilder(@" /* Services_Insert (with id) */ insert into services (service_id, service_type, service_sid, service_uri, service_description, service_local, service_enabled, service_last_edit, service_last_status) values (?ID, ?TYPE, ?SID, ?URI, ?DESC, ?LOCAL, ?ENABLED, ?TIMESTAMP, ?LASTSTATUS); "); query.AppendLine(string.Format("select {0} into @service_id;", service.Id)); query.AppendLine(string.Format("select {0} as service_id;", service.Id)); } if (service.Preferences != null && service.Preferences.Count > 0) { query.Append("insert into service_prefs (service_id, pref_name, pref_value) values "); for (int i = 0; i < service.Preferences.AllKeys.Length; i++) { string key = DataCommand.MakeSqlSafe(service.Preferences.AllKeys[i]); string val = DataCommand.MakeSqlSafe(service.Preferences[key]); query.AppendFormat("{0}(@service_id, '{1}', '{2}')\n", i > 0 ? "," : string.Empty, key, val); } query.AppendLine(";"); } if (service.Config != null && service.Config.Count > 0) { query.Append("insert into service_config (service_id, config_name, config_value) values "); for (int i = 0; i < service.Config.AllKeys.Length; i++) { string key = DataCommand.MakeSqlSafe(service.Config.AllKeys[i]); string val = DataCommand.MakeSqlSafe(service.Config[key]); query.AppendFormat("{0}(@service_id, '{1}', '{2}')\n", i > 0 ? "," : string.Empty, key, val); } query.AppendLine(";"); } uint serviceId = 0; try { serviceId = Catalog.NewQuery(query.ToString()) .With("ID", service.Id) .With("TYPE", service.Type.ToString()) .With("SID", service.SID) .With("URI", service.Uri) .With("DESC", service.Description) .With("LOCAL", service.ServiceLocal) .With("ENABLED", service.ServiceEnabled) .With("TIMESTAMP", service.ServiceLastEdit) .With("LASTSTATUS", service.ServiceLastStatus) .ReadAsUInt() ?? 0; } catch (MySqlException e) { // catch Duplicate Key (1062) if (e.Number == 1062) { serviceId = service.Id; } else { throw; } } return(serviceId); }