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);
        }
예제 #4
0
        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);
        }