public async Task GetModuleOnBehalfOf() { // Setup ServiceIdentity results string parentEdgeId = "edge1"; string childEdgeId = "edge2"; string moduleId = "module1"; string deviceScope = "deviceScope1"; string parentScope = "parentScope1"; string generationId = "generation1"; var authentication = new ServiceAuthentication(new SymmetricKeyAuthentication(this.primaryKey, this.secondaryKey)); var resultDeviceIdentity = new ServiceIdentity(childEdgeId, null, deviceScope, new List <string>() { parentScope }, generationId, Enumerable.Empty <string>(), authentication, ServiceIdentityStatus.Enabled); var resultModuleIdentity = new ServiceIdentity(childEdgeId, moduleId, null, new List <string>() { deviceScope }, generationId, Enumerable.Empty <string>(), authentication, ServiceIdentityStatus.Enabled); var resultIdentities = new List <ServiceIdentity>() { resultDeviceIdentity, resultModuleIdentity }; var authChainMapping = new Dictionary <string, string>(); string targetId = childEdgeId + "/" + moduleId; authChainMapping.Add(targetId, $"{targetId};{childEdgeId};{parentEdgeId};edgeroot"); var controller = MakeController(childEdgeId, resultIdentities, authChainMapping); // Act controller.Request.Headers.Add(Constants.OriginEdgeHeaderKey, $"{childEdgeId}"); var request = new IdentityOnBehalfOfRequest(childEdgeId, moduleId, $"{childEdgeId};{parentEdgeId}"); await controller.GetDeviceAndModuleOnBehalfOfAsync(parentEdgeId, "$edgeHub", request); // Verify EdgeHub result types var expectedAuth = new AuthenticationMechanism() { SymmetricKey = new SymmetricKey() { PrimaryKey = this.primaryKey, SecondaryKey = this.secondaryKey } }; var expectedDeviceIdentities = new List <EdgeHubScopeDevice>() { new EdgeHubScopeDevice(childEdgeId, generationId, DeviceStatus.Enabled, expectedAuth, new DeviceCapabilities(), deviceScope, new List <string> { parentScope }) }; var expectedModuleIdentities = new List <EdgeHubScopeModule>() { new EdgeHubScopeModule(moduleId, childEdgeId, generationId, expectedAuth) }; var responseExpected = new EdgeHubScopeResultSuccess(expectedDeviceIdentities, expectedModuleIdentities); var responseExpectedJson = JsonConvert.SerializeObject(responseExpected); var responseActualBytes = GetResponseBodyBytes(controller); var responseActualJson = Encoding.UTF8.GetString(responseActualBytes); Assert.Equal((int)HttpStatusCode.OK, controller.HttpContext.Response.StatusCode); Assert.Equal(responseExpectedJson, responseActualJson); }
public async Task HandleGetDeviceAndModuleOnBehalfOfAsync( string actorDeviceId, string actorModuleId, string targetDeviceId, string targetModuleId, string authChain, string originatorDeviceId, string authChainToTarget, HttpStatusCode expectedStatus) { // Setup var request = new IdentityOnBehalfOfRequest(targetDeviceId, targetModuleId, authChain); var identitiesCache = new Mock <IDeviceScopeIdentitiesCache>(); string targetId = targetDeviceId + (string.IsNullOrWhiteSpace(targetModuleId) ? string.Empty : $"/{targetModuleId}"); identitiesCache.Setup(i => i.RefreshServiceIdentityOnBehalfOf(targetId, originatorDeviceId)).Returns(Task.CompletedTask); var targetServiceIdentity = new ServiceIdentity(targetId, "dummy", Enumerable.Empty <string>(), new ServiceAuthentication(ServiceAuthenticationType.None), ServiceIdentityStatus.Enabled); identitiesCache.Setup(i => i.GetServiceIdentity(targetId)).Returns(Task.FromResult(Option.Some(targetServiceIdentity))); identitiesCache.Setup(i => i.GetAuthChain(targetId)).Returns(Task.FromResult(Option.Some(authChainToTarget))); // Act EdgeHubScopeResult edgeHubScopeResult = await DeviceScopeController.HandleGetDeviceAndModuleOnBehalfOfAsync(actorDeviceId, actorModuleId, request, identitiesCache.Object); // Verity Assert.Equal(expectedStatus, edgeHubScopeResult.Status); }
async Task <ScopeResult> GetIdentityOnBehalfOfInternalAsync(Uri uri, string deviceId, Option <string> moduleId, string onBehalfOfDevice) { HttpClient client = this.proxy .Map(p => new HttpClient(new HttpClientHandler { Proxy = p }, disposeHandler: true)) .GetOrElse(() => new HttpClient()); using (var msg = new HttpRequestMessage(HttpMethod.Post, uri)) { // Get the auth-chain for the EdgeHub we're acting OnBehalfOf string onBehalfOfEdgeHub = $"{onBehalfOfDevice}/{Constants.EdgeHubModuleId}"; Option <string> maybeAuthChain = await this.serviceIdentityHierarchy.GetEdgeAuthChain(onBehalfOfEdgeHub); string authChain = maybeAuthChain.Expect(() => new InvalidOperationException($"No valid authentication chain for {onBehalfOfEdgeHub}")); // We must pass the origin Edge ID along upstream, so the root // can know which Edge to act OnBehalfOf when calling IoT Hub msg.Headers.Add(Constants.OriginEdgeHeaderKey, onBehalfOfDevice); var payload = new IdentityOnBehalfOfRequest(deviceId, moduleId.OrDefault(), authChain); string token = await this.edgeHubTokenProvider.GetTokenAsync(Option.None <TimeSpan>()); msg.Headers.Add(HttpRequestHeader.Authorization.ToString(), token); msg.Content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); HttpResponseMessage response = await client.SendAsync(msg); string content = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { var scopeResult = JsonConvert.DeserializeObject <ScopeResult>(content); Events.GotValidResult(); return(scopeResult); } else { throw new DeviceScopeApiException("Error getting device scope result from upstream", response.StatusCode, content); } } }
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)); 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) { EdgeHubScopeResult reqResult = await this.HandleGetDeviceAndModuleOnBehalfOfAsync(actorDeviceId, actorModuleId, request); 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 static void ReceivedIdentityOnBehalfOfRequest(string actorDeviceId, string actorModuleId, IdentityOnBehalfOfRequest request) { Log.LogInformation((int)EventIds.ReceivedIdentityOnBehalfOfRequest, $"Received get scope request: actorId: {actorDeviceId}/{actorModuleId}, authChain: {request.AuthChain}, targetDevice: {request.TargetDeviceId}, targetModule: {request.TargetModuleId}"); }
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)); }