async Task <EdgeHubScopeResult> HandleDevicesAndModulesInTargetDeviceScopeAsync(string actorDeviceId, string actorModuleId, NestedScopeRequest request) { Events.ReceivedScopeRequest(actorDeviceId, actorModuleId, request); Preconditions.CheckNonWhiteSpace(request.AuthChain, nameof(request.AuthChain)); if (!this.TryGetTargetDeviceId(request.AuthChain, out string targetDeviceId)) { return(new EdgeHubScopeResultError(HttpStatusCode.BadRequest, Events.InvalidRequestAuthchain(request.AuthChain))); } // Check that the actor device is authorized to act OnBehalfOf the target IEdgeHub edgeHub = await this.edgeHubGetter; IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); if (!await this.AuthorizeActorAsync(identitiesCache, actorDeviceId, actorModuleId, targetDeviceId)) { return(new EdgeHubScopeResultError(HttpStatusCode.Unauthorized, Events.UnauthorizedActor(actorDeviceId, actorModuleId, targetDeviceId))); } // Get the children of the target device and the target device itself; IList <ServiceIdentity> identities = await identitiesCache.GetDevicesAndModulesInTargetScopeAsync(targetDeviceId); Option <ServiceIdentity> targetDevice = await identitiesCache.GetServiceIdentity(targetDeviceId); targetDevice.ForEach(d => identities.Add(d)); // Construct the result from the identities Events.SendingScopeResult(targetDeviceId, identities); return(MakeResultFromIdentities(identities)); }
public async Task GetDeviceAndModuleOnBehalfOfAsync([FromRoute] string actorDeviceId, [FromRoute] string actorModuleId, [FromBody] IdentityOnBehalfOfRequest request) { actorDeviceId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(actorDeviceId, nameof(actorDeviceId))); actorModuleId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(actorModuleId, nameof(actorModuleId))); Preconditions.CheckNonWhiteSpace(request.AuthChain, nameof(request.AuthChain)); if (actorModuleId != Constants.EdgeHubModuleId) { // Only child EdgeHubs are allowed to act OnBehalfOf of devices/modules. var result = new EdgeHubScopeResultError(HttpStatusCode.Unauthorized, Events.UnauthorizedActor(actorDeviceId, actorModuleId, string.IsNullOrWhiteSpace(request.TargetModuleId) ? request.TargetDeviceId : $"{request.TargetDeviceId}/{request.TargetModuleId}")); await this.SendResponse(result.Status, JsonConvert.SerializeObject(result)); } IHttpRequestAuthenticator authenticator = await this.authenticatorGetter; HttpAuthResult authResult = await authenticator.AuthenticateAsync(actorDeviceId, Option.Some(actorModuleId), Option.Some(request.AuthChain), this.HttpContext); if (authResult.Authenticated) { IEdgeHub edgeHub = await this.edgeHubGetter; IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); EdgeHubScopeResult reqResult = await HandleGetDeviceAndModuleOnBehalfOfAsync(actorDeviceId, actorModuleId, request, identitiesCache); await this.SendResponse(reqResult.Status, JsonConvert.SerializeObject(reqResult)); } else { var result = new EdgeHubScopeResultError(HttpStatusCode.Unauthorized, authResult.ErrorMessage); await this.SendResponse(result.Status, JsonConvert.SerializeObject(result)); } }
public async Task DeleteModuleAsync( [FromRoute] string deviceId, [FromRoute] string moduleId) { try { Events.ReceivedRequest(nameof(this.DeleteModuleAsync), deviceId, moduleId); try { deviceId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(deviceId, nameof(deviceId))); moduleId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(moduleId, nameof(moduleId))); } catch (Exception ex) { Events.BadRequest(nameof(this.DeleteModuleAsync), ex.Message); await this.SendResponseAsync(HttpStatusCode.BadRequest, FormatErrorResponseMessage(ex.Message)); return; } IHttpRequestAuthenticator authenticator = await this.authenticatorGetter; if (!await AuthenticateAsync(deviceId, Option.None <string>(), Option.None <string>(), this.HttpContext, authenticator)) { await this.SendResponseAsync(HttpStatusCode.Unauthorized); return; } IEdgeHub edgeHub = await this.edgeHubGetter; IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); Option <string> targetAuthChain = await identitiesCache.GetAuthChain(deviceId); if (!targetAuthChain.HasValue) { Events.AuthorizationFail_NoAuthChain(deviceId); await this.SendResponseAsync(HttpStatusCode.Unauthorized); return; } string edgeDeviceId = edgeHub.GetEdgeDeviceId(); var requestData = new DeleteModuleOnBehalfOfData($"{targetAuthChain.OrDefault()}", moduleId); RegistryApiHttpResult result = await this.apiClient.DeleteModuleAsync(edgeDeviceId, requestData); await this.SendResponseAsync(result.StatusCode, result.JsonContent); Events.CompleteRequest(nameof(this.DeleteModuleAsync), edgeDeviceId, requestData.AuthChain, result); } catch (Exception ex) { Events.InternalServerError(nameof(this.DeleteModuleAsync), ex); await this.SendResponseAsync(HttpStatusCode.InternalServerError, FormatErrorResponseMessage(ex.ToString())); } }
async Task <EdgeHubScopeResult> HandleDevicesAndModulesInTargetDeviceScopeAsync(string actorDeviceId, string actorModuleId, NestedScopeRequest request) { Events.ReceivedScopeRequest(actorDeviceId, actorModuleId, request); if (!AuthChainHelpers.TryGetTargetDeviceId(request.AuthChain, out string targetDeviceId)) { return(new EdgeHubScopeResultError(HttpStatusCode.BadRequest, Events.InvalidRequestAuthchain(request.AuthChain))); } // Get the children of the target device and the target device itself; IEdgeHub edgeHub = await this.edgeHubGetter; IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); IList <ServiceIdentity> identities = await identitiesCache.GetDevicesAndModulesInTargetScopeAsync(targetDeviceId); Option <ServiceIdentity> targetDevice = await identitiesCache.GetServiceIdentity(targetDeviceId); targetDevice.ForEach(d => identities.Add(d)); // Construct the result from the identities Events.SendingScopeResult(targetDeviceId, identities); return(MakeResultFromIdentities(identities)); }
internal static async Task <Try <string> > AuthorizeOnBehalfOf( string actorDeviceId, string authChain, string source, HttpContext httpContext, IEdgeHub edgeHub, IHttpRequestAuthenticator authenticator) { if (!AuthChainHelpers.TryGetTargetDeviceId(authChain, out string targetDeviceId)) { Events.InvalidRequestAuthChain(source, authChain); return(Try <string> .Failure(new ValidationException(HttpStatusCode.BadRequest, FormatErrorResponseMessage($"Invalid request auth chain {authChain}.")))); } if (!await AuthenticateAsync(actorDeviceId, Option.Some(Constants.EdgeHubModuleId), Option.Some(authChain), httpContext, authenticator)) { return(Try <string> .Failure(new ValidationException(HttpStatusCode.Unauthorized))); } IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); Option <string> targetAuthChain = await identitiesCache.GetAuthChain(targetDeviceId); return(targetAuthChain.Match( ac => { if (!AuthChainHelpers.ValidateAuthChain(actorDeviceId, targetDeviceId, ac)) { Events.AuthorizationFail_InvalidAuthChain(actorDeviceId, targetDeviceId, ac); return Try <string> .Failure(new ValidationException(HttpStatusCode.Unauthorized)); } return ac; }, () => { Events.AuthorizationFail_NoAuthChain(targetDeviceId); return Try <string> .Failure(new ValidationException(HttpStatusCode.Unauthorized)); })); }
async Task <EdgeHubScopeResult> HandleGetDeviceAndModuleOnBehalfOfAsync(string actorDeviceId, string actorModuleId, IdentityOnBehalfOfRequest request) { Events.ReceivedIdentityOnBehalfOfRequest(actorDeviceId, actorModuleId, request); Preconditions.CheckNonWhiteSpace(request.TargetDeviceId, nameof(request.TargetDeviceId)); bool isModule = false; string targetId = request.TargetDeviceId; if (!request.TargetModuleId.IsNullOrWhiteSpace()) { isModule = true; targetId += "/" + request.TargetModuleId; } IEdgeHub edgeHub = await this.edgeHubGetter; // Check if the actor has provided the originating EdgeHub ID, // if not, then we must be by definition by the origin. string originatingEdge = edgeHub.GetEdgeDeviceId(); if (this.Request.Headers.TryGetValue(Constants.OriginEdgeHeaderKey, out StringValues originHeader) && originHeader.Count > 0) { originatingEdge = originHeader.First(); } // We must always forward the call further upstream first, // as this is invoked for refreshing an identity on-demand, // and we don't know whether our cache is out-of-date. IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); await identitiesCache.RefreshServiceIdentityOnBehalfOf(targetId, originatingEdge); Option <ServiceIdentity> targetIdentity = await identitiesCache.GetServiceIdentity(targetId); if (!targetIdentity.HasValue) { // Identity still doesn't exist, this can happen if the identity // is newly added and we couldn't refresh the individual identity // because we don't know where it resides in the nested hierarchy. // In this case our only recourse is to refresh the whole cache // and hope the identity shows up. identitiesCache.InitiateCacheRefresh(); await identitiesCache.WaitForCacheRefresh(TimeSpan.FromSeconds(100)); targetIdentity = await identitiesCache.GetServiceIdentity(targetId); } // Add the identity to the result var identityList = new List <ServiceIdentity>(); targetIdentity.ForEach(i => identityList.Add(i)); // If the target is a module, we also need to // include the parent device as well to match // IoT Hub API behavior if (isModule) { Option <ServiceIdentity> device = await identitiesCache.GetServiceIdentity(request.TargetDeviceId); device.ForEach(i => identityList.Add(i)); } Events.SendingScopeResult(targetId, identityList); return(MakeResultFromIdentities(identityList)); }
public async Task CreateOrUpdateModuleAsync( [FromRoute] string deviceId, [FromRoute] string moduleId, [FromHeader(Name = "if-match")] string ifMatchHeader, [FromBody] Module module) { try { Events.ReceivedRequest(nameof(this.CreateOrUpdateModuleAsync), deviceId, moduleId); try { deviceId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(deviceId, nameof(deviceId))); moduleId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(moduleId, nameof(moduleId))); Preconditions.CheckNotNull(module, nameof(module)); if (!string.Equals(deviceId, module.DeviceId) || !string.Equals(moduleId, module.Id)) { throw new ApplicationException("Device Id or module Id doesn't match between request URI and body."); } } catch (Exception ex) { Events.BadRequest(nameof(this.CreateOrUpdateModuleAsync), ex.Message); await this.SendResponseAsync(HttpStatusCode.BadRequest, FormatErrorResponseMessage(ex.Message)); return; } IHttpRequestAuthenticator authenticator = await this.authenticatorGetter; if (!await AuthenticateAsync(deviceId, Option.None <string>(), Option.None <string>(), this.HttpContext, authenticator)) { await this.SendResponseAsync(HttpStatusCode.Unauthorized); return; } IEdgeHub edgeHub = await this.edgeHubGetter; IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); Option <string> targetAuthChain = await identitiesCache.GetAuthChain(deviceId); if (!targetAuthChain.HasValue) { Events.AuthorizationFail_NoAuthChain(deviceId); await this.SendResponseAsync(HttpStatusCode.Unauthorized); return; } string edgeDeviceId = edgeHub.GetEdgeDeviceId(); var requestData = new CreateOrUpdateModuleOnBehalfOfData($"{targetAuthChain.OrDefault()}", module); RegistryApiHttpResult result = await this.apiClient.PutModuleAsync(edgeDeviceId, requestData, ifMatchHeader); await this.SendResponseAsync(result.StatusCode, result.JsonContent); Events.CompleteRequest(nameof(this.CreateOrUpdateModuleAsync), edgeDeviceId, requestData.AuthChain, result); } catch (Exception ex) { Events.InternalServerError(nameof(this.CreateOrUpdateModuleAsync), ex); await this.SendResponseAsync(HttpStatusCode.InternalServerError, FormatErrorResponseMessage(ex.ToString())); } }
public async Task ListModulesAsync( [FromRoute] string deviceId) { try { Events.ReceivedRequest(nameof(this.ListModulesAsync), deviceId); if (!this.HttpContext.Request.Query.ContainsKey("api-version")) { Dictionary <string, string> headers = new Dictionary <string, string>(); headers.Add("iothub-errorcode", "InvalidProtocolVersion"); await this.SendResponseAsync(HttpStatusCode.BadRequest, headers, string.Empty); return; } try { deviceId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(deviceId, nameof(deviceId))); } catch (Exception ex) { Events.BadRequest(nameof(this.ListModulesAsync), ex.Message); await this.SendResponseAsync(HttpStatusCode.BadRequest, FormatErrorResponseMessage(ex.Message)); return; } IHttpRequestAuthenticator authenticator = await this.authenticatorGetter; if (!await AuthenticateAsync(deviceId, Option.None <string>(), Option.None <string>(), this.HttpContext, authenticator)) { await this.SendResponseAsync(HttpStatusCode.Unauthorized); return; } IEdgeHub edgeHub = await this.edgeHubGetter; IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); Option <string> targetAuthChain = await identitiesCache.GetAuthChain(deviceId); if (!targetAuthChain.HasValue) { Events.AuthorizationFail_NoAuthChain(deviceId); await this.SendResponseAsync(HttpStatusCode.Unauthorized); return; } string edgeDeviceId = edgeHub.GetEdgeDeviceId(); var requestData = new ListModulesOnBehalfOfData($"{targetAuthChain.OrDefault()}"); RegistryApiHttpResult result = await this.apiClient.ListModulesAsync(edgeDeviceId, requestData); await this.SendResponseAsync(result.StatusCode, result.JsonContent); Events.CompleteRequest(nameof(this.ListModulesAsync), edgeDeviceId, requestData.AuthChain, result); } catch (Exception ex) { Events.InternalServerError(nameof(this.ListModulesAsync), ex); await this.SendResponseAsync(HttpStatusCode.InternalServerError, FormatErrorResponseMessage(ex.ToString())); } }
public async Task DeleteModuleOnBehalfOfAsync( [FromRoute] string actorDeviceId, [FromBody] DeleteModuleOnBehalfOfData requestData) { try { Events.ReceivedOnBehalfOfRequest(nameof(this.DeleteModuleOnBehalfOfAsync), actorDeviceId, Events.GetAdditionalInfo(requestData)); try { Preconditions.CheckNonWhiteSpace(actorDeviceId, nameof(actorDeviceId)); Preconditions.CheckNotNull(requestData, nameof(requestData)); Preconditions.CheckNonWhiteSpace(requestData.AuthChain, nameof(requestData.AuthChain)); Preconditions.CheckNonWhiteSpace(requestData.ModuleId, nameof(requestData.ModuleId)); } catch (Exception ex) { Events.BadRequest(nameof(this.DeleteModuleOnBehalfOfAsync), ex.Message); await this.SendResponseAsync(HttpStatusCode.BadRequest, FormatErrorResponseMessage(ex.ToString())); return; } actorDeviceId = WebUtility.UrlDecode(actorDeviceId); if (!AuthChainHelpers.TryGetTargetDeviceId(requestData.AuthChain, out string targetDeviceId)) { Events.InvalidRequestAuthChain(nameof(this.DeleteModuleOnBehalfOfAsync), requestData.AuthChain); await this.SendResponseAsync(HttpStatusCode.BadRequest, FormatErrorResponseMessage($"Invalid request auth chain {requestData.AuthChain}.")); return; } if (!await this.AuthenticateAsync(actorDeviceId, Option.Some(Constants.EdgeHubModuleId), Option.Some(requestData.AuthChain))) { await this.SendResponseAsync(HttpStatusCode.Unauthorized); return; } IEdgeHub edgeHub = await this.edgeHubGetter; IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); Option <string> targetAuthChain = await identitiesCache.GetAuthChain(targetDeviceId); if (!targetAuthChain.HasValue) { Events.AuthorizationFail_NoAuthChain(targetDeviceId); await this.SendResponseAsync(HttpStatusCode.Unauthorized); return; } string edgeDeviceId = edgeHub.GetEdgeDeviceId(); RegistryApiHttpResult result = await this.apiClient.DeleteModuleAsync( edgeDeviceId, new DeleteModuleOnBehalfOfData($"{targetAuthChain.OrDefault()}", requestData.ModuleId)); await this.SendResponseAsync(result.StatusCode, result.JsonContent); Events.CompleteRequest(nameof(this.DeleteModuleOnBehalfOfAsync), edgeDeviceId, targetAuthChain.OrDefault(), result); } catch (Exception ex) { Events.InternalServerError(nameof(this.DeleteModuleOnBehalfOfAsync), ex); await this.SendResponseAsync(HttpStatusCode.InternalServerError, FormatErrorResponseMessage(ex.ToString())); } }