private async Task <APIMSubscription> CreateSubscription(User user, string accessToken, string displayName, string scope, Guid primaryKey, Guid secondaryKey, string state) { APIMSubscription apimSubscription = null; string userId = $"/users/{user.name}"; string subscriptionName = displayName.Replace(" ", "-").ToLower(); string url = $"{_apimUrl}/subscriptions/{subscriptionName}?api-version=2019-12-01"; string requestBody = "{ \"properties\": { \"primaryKey\": \"" + primaryKey + "\", \"scope\": \"" + scope + "\", \"secondaryKey\": \"" + secondaryKey + "\", \"displayName\": \"" + displayName + "\", \"ownerId\": \"" + userId + "\", \"state\": \"" + state + "\" } }"; _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("SharedAccessSignature", accessToken); HttpResponseMessage response = await _httpClient.PutAsync(url, new StringContent(requestBody, Encoding.UTF8, "application/json")); if (response.IsSuccessStatusCode) { string responseContent = await response.Content.ReadAsStringAsync(); apimSubscription = JsonConvert.DeserializeObject <APIMSubscription>(responseContent); apimSubscription.properties.scope = scope; } else { string responseContent = await response.Content.ReadAsStringAsync(); } return(apimSubscription); }
public async Task <APIMSubscription> CreateOrgSubscription(string displayName, string scope, Guid primaryKey, Guid secondaryKey, string email, string firstName, string lastName) { APIMSubscription apimSubscription = null; string accessToken = GenerateAccessToken(); User user = await GetUser(email, accessToken); if (user == null) { user = await CreateUser(accessToken, string.Empty, email, firstName, lastName); } apimSubscription = await CreateSubscription(user, accessToken, displayName, scope, primaryKey, secondaryKey, "active"); return(apimSubscription); }
public async Task <APIMSubscription> CreateSubscription(string displayName, string scope, Guid primaryKey, Guid secondaryKey, string objectId, string email, string firstName, string lastName) { APIMSubscription apimSubscription = null; string accessToken = GenerateAccessToken(); User user = await GetUser(email, accessToken); if (user == null) { user = await CreateUser(accessToken, objectId, email, firstName, lastName); } displayName = $"{displayName} {objectId}"; apimSubscription = await CreateSubscription(user, accessToken, displayName, scope, primaryKey, secondaryKey, "submitted"); return(apimSubscription); }
public async Task <IActionResult> Index() { if (User.Identity.IsAuthenticated) { string operation = Request.Query["operation"]; string salt = Request.Query["salt"]; string sig = Request.Query["sig"]; string emailAddress = string.Empty; string redirectUrl = string.Empty; if (operation == "SignOut") { return(RedirectToAction("SignOut")); } else if (operation == "Subscribe") { string productId = Request.Query["productId"]; string userId = Request.Query["userId"]; bool isSignatureValid = false; using (var encoder = new HMACSHA512(Convert.FromBase64String(_delegationValidationKey))) { string signature = Convert.ToBase64String(encoder.ComputeHash(Encoding.UTF8.GetBytes((salt + "\n" + productId + "\n" + userId)))); isSignatureValid = sig == signature; } if (isSignatureValid) { // Create subscription string accessToken = GenerateAccessToken(); Product product = await GetProduct(productId, accessToken); if (product != null) { string state = "active"; if (product.properties.approvalRequired) { state = "submitted"; } Guid primaryKey = Guid.NewGuid(); Guid secondaryKey = Guid.NewGuid(); APIMSubscription subscription = await CreateSubscription(userId, accessToken, $"{product.properties.displayName} Subscription {userId}", $"/products/{productId}", primaryKey, secondaryKey, state); if (subscription != null) { redirectUrl = $"{_configuration.GetValue<string>("developerPortalSignoutUrl")}/profile"; return(new RedirectResult(redirectUrl)); } else { // Subscription creation failed } } { // Failed to retrieve product } } else { // Invalid signature } } else if (operation == "Unsubscribe") { string subscriptionId = Request.Query["subscriptionId"]; bool isSignatureValid = false; using (var encoder = new HMACSHA512(Convert.FromBase64String(_delegationValidationKey))) { string signature = Convert.ToBase64String(encoder.ComputeHash(Encoding.UTF8.GetBytes((salt + "\n" + subscriptionId)))); isSignatureValid = sig == signature; } if (isSignatureValid) { // Delete subscription string accessToken = GenerateAccessToken(); await DeleteSubscription(subscriptionId, accessToken); redirectUrl = $"{_configuration.GetValue<string>("developerPortalSignoutUrl")}/profile"; return(new RedirectResult(redirectUrl)); } } else if (operation == "Renew") { string subscriptionId = Request.Query["subscriptionId"]; bool isSignatureValid = false; using (var encoder = new HMACSHA512(Convert.FromBase64String(_delegationValidationKey))) { string signature = Convert.ToBase64String(encoder.ComputeHash(Encoding.UTF8.GetBytes((salt + "\n" + subscriptionId)))); isSignatureValid = sig == signature; } if (isSignatureValid) { // Renew subscription // Currently, APIM does not support expiration for subscriptions // Planned for future release } } else // SignIn or SignUp - handled by Azure AD B2C { string returnUrl = Request.Query["returnUrl"]; bool isSignatureValid = false; using (var encoder = new HMACSHA512(Convert.FromBase64String(_delegationValidationKey))) { string signature = Convert.ToBase64String(encoder.ComputeHash(Encoding.UTF8.GetBytes(salt + "\n" + returnUrl))); isSignatureValid = sig == signature; } if (isSignatureValid) { foreach (Claim claim in User.Claims) { if (claim.Type == "mail") { emailAddress = claim.Value.ToString(); break; } } if (!string.IsNullOrEmpty(emailAddress)) { // Lookup APIM user by email address string accessToken = GenerateAccessToken(); User user = await GetUser(emailAddress, accessToken); if (user == null) { // Unknown user } // Get APIM token string sharedAccessToken = await GetSharedAccessToken(user.name, accessToken); if (!string.IsNullOrEmpty(sharedAccessToken)) { redirectUrl = $"{_configuration.GetValue<string>("developerPortalSSOUrl")}?token={HttpUtility.UrlEncode(sharedAccessToken)}&returnUrl={HttpUtility.UrlEncode(returnUrl)}"; return(new RedirectResult(redirectUrl)); } else { // Failed to retrieve token } } } else { // Invalid signature } } } return(View()); }
// GET api/<controller>/5 public async Task <HttpResponseMessage> Get(string id) { HttpResponseMessage result = new HttpResponseMessage(); List <KeyValuePair <string, string> > queryString = Request.GetQueryNameValuePairs().ToList(); string objectId = queryString.FirstOrDefault(q => q.Key == "objectId").Value; string email = queryString.FirstOrDefault(q => q.Key == "email").Value; string firstName = queryString.FirstOrDefault(q => q.Key == "firstName").Value; string lastName = queryString.FirstOrDefault(q => q.Key == "lastName").Value; if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(objectId) || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName)) { result.StatusCode = HttpStatusCode.BadRequest; result.Content = new StringContent("Please pass an id, objectId, email, firstName, and lastName on the querystring"); } else { string partitionKey = id.Substring(0, 1).ToLower(); OrganizationSubscription subscription = await _registrationService.GetOrganizationSubscription(partitionKey, id); if (subscription == null) { // Create Azure AD Application Registration for the Organization Guid uniqueId = Guid.NewGuid(); Application application = new Application(); application.DisplayName = $"AAD - {id} Client Application"; application.IdentifierUris = new List <string>(); application.IdentifierUris.Add($"https://{ConfigurationManager.AppSettings["TENANT"]}/{uniqueId}"); application.PasswordCredentials = new List <PasswordCredential>(); var startDate = DateTime.Now; Byte[] bytes = new Byte[32]; using (var rand = System.Security.Cryptography.RandomNumberGenerator.Create()) { rand.GetBytes(bytes); } string clientSecret = Convert.ToBase64String(bytes); application.PasswordCredentials.Add(new PasswordCredential() { CustomKeyIdentifier = null, StartDate = startDate, EndDate = new DateTime(2299, 12, 31, 5, 0, 0, 0), KeyId = Guid.NewGuid(), Value = clientSecret }); application.RequiredResourceAccess = new List <RequiredResourceAccess>(); RequiredResourceAccess graphResourceAccess = new RequiredResourceAccess() { ResourceAccess = new List <ResourceAccess>(), ResourceAppId = "00000003-0000-0000-c000-000000000000" }; graphResourceAccess.ResourceAccess.Add(new ResourceAccess() { Id = new Guid("37f7f235-527c-4136-accd-4a02d197296e"), Type = "Scope" }); graphResourceAccess.ResourceAccess.Add(new ResourceAccess() { Id = new Guid("7427e0e9-2fba-42fe-b0c0-848c9e6a8182"), Type = "Scope" }); RequiredResourceAccess apimResourceAccess = new RequiredResourceAccess() { ResourceAccess = new List <ResourceAccess>(), ResourceAppId = "30fe3279-fbb4-4a13-b1f8-7c5f2ea9e6df" }; apimResourceAccess.ResourceAccess.Add(new ResourceAccess() { Id = new Guid("f9bcce35-145a-4199-bf1b-948467774061"), Type = "Role" }); application.RequiredResourceAccess.Add(graphResourceAccess); application.RequiredResourceAccess.Add(apimResourceAccess); application.ReplyUrls = new List <string>(); application.ReplyUrls.Add($"msapp://{uniqueId}"); string clientId = await _appService.Create(application); // Create APIM subscription key for the organization Guid primaryKey = Guid.NewGuid(); Guid secondaryKey = Guid.NewGuid(); APIMSubscription apimSubscription = await _subscriptionService.CreateOrgSubscription($"APIM {id} Subscription", "/products/starter", primaryKey, secondaryKey, $"{id}@{_orgEmailDomain}", id, id); // Store subscription information in Table Storage OrganizationSubscription organizationSubscription = new OrganizationSubscription() { Organization = id, PrimarySubscriptionKey = apimSubscription.properties.primaryKey, SecondarySubscriptionKey = apimSubscription.properties.secondaryKey, Scope = apimSubscription.properties.scope, ClientId = clientId, ClientSecret = clientSecret }; OrganizationEntity organizationEntity = new OrganizationEntity(organizationSubscription); await _registrationService.CreateOrganizationSubscription(organizationEntity); // Create pending APIM subscription for the user APIMSubscription apimUserSubscription = await _subscriptionService.CreateSubscription($"APIM {id} Subscription", "/products/starter", Guid.NewGuid(), Guid.NewGuid(), objectId, email, firstName, lastName); // No user subscriptions have been approved yet so return masked values ResponseContent responseContent = new ResponseContent { version = "1.0.0", status = (int)HttpStatusCode.OK, organization = id, primarySubscriptionKey = MASKED_VALUE, secondarySubscriptionKey = MASKED_VALUE, clientId = MASKED_VALUE, clientSecret = MASKED_VALUE }; result.StatusCode = HttpStatusCode.OK; result.Content = new StringContent(JsonConvert.SerializeObject(responseContent), Encoding.UTF8, "application/json"); } else { string state = string.Empty; bool userHasSubscription = false; UserSubscriptions userSubscriptions = await _subscriptionService.GetUserSubscriptions(email); if (userSubscriptions != null && userSubscriptions.count > 0) { foreach (UserSubscription userSubscription in userSubscriptions.value) { if (userSubscription.properties.scope.EndsWith(subscription.Scope, StringComparison.InvariantCultureIgnoreCase)) { state = userSubscription.properties.state; userHasSubscription = true; break; } } } if (!userHasSubscription) { APIMSubscription apimSubscription = await _subscriptionService.CreateSubscription($"APIM {id} Subscription", "/products/starter", Guid.NewGuid(), Guid.NewGuid(), objectId, email, firstName, lastName); state = apimSubscription.properties.state; } ResponseContent responseContent = null; if (state == "active") // User has an approved subscription - share the organization values { responseContent = new ResponseContent { version = "1.0.0", status = (int)HttpStatusCode.OK, organization = id, primarySubscriptionKey = subscription.PrimarySubscriptionKey, secondarySubscriptionKey = subscription.SecondarySubscriptionKey, clientId = subscription.ClientId, clientSecret = subscription.ClientSecret }; } else // User has a pending subscription - return masked values { responseContent = new ResponseContent { version = "1.0.0", status = (int)HttpStatusCode.OK, organization = id, primarySubscriptionKey = MASKED_VALUE, secondarySubscriptionKey = MASKED_VALUE, clientId = MASKED_VALUE, clientSecret = MASKED_VALUE }; } result.StatusCode = HttpStatusCode.OK; result.Content = new StringContent(JsonConvert.SerializeObject(responseContent), Encoding.UTF8, "application/json"); } } return(result); }