bpr
bpr

Reputation: 1

Authorization Error 403: access denied in Android Management API w/o using Google Cloud Project Account Credentials

When I'm using the Google Cloud Project Account Credentials to Login then everything like (create new enterprise, apply policies, see enrolled devices...). I can easily achieved but when trying to login with an Enterprise created with the Google_Cloud_Project_Account thru those enterprise, I'm unable perform any above operation as I'm getting "403 access denied error".

For Ex: We have Google Cloud Project Account with the name: [email protected] We have created two enterprises like [email protected] and [email protected]

But when we try to apply policies in either of the enterprise ([email protected] or [email protected]), we are getting errors like below: Error 403: access_denied The developer hasn’t given you access to this app. It’s currently being tested and it hasn’t been verified by Google. If you think you should have access, contact the developer ([email protected]).

So, I can do any operation using [email protected] but unable to perform any operation using ([email protected] or [email protected]) which are the child enterprise of [email protected].

For clarity, I have shared my code. Please let me know where I need to change or what exactly I need to do.

Enterprise Post Method:

 [GoogleScopedAuthorize(AndroidManagementService.ScopeConstants.Androidmanagement)]
        [HttpPost]
        public async Task<IActionResult> CreateEnterprise([FromServices] IGoogleAuthProvider auth)
        {
            try
            {
                EnterpriseDto enterpriseModel = new();

                #region OAuthFlow
                // Check if the required scopes have been granted. 
                if (await auth.RequireScopesAsync(AndroidManagementService.ScopeConstants.Androidmanagement) is IActionResult authResult)
                {
                    return authResult;
                }

                //The required scopes have now been granted.
                GoogleCredential cred = await auth.GetCredentialAsync();
                var service = new AndroidManagementService(new BaseClientService.Initializer
                {
                    HttpClientInitializer = cred.CreateScoped(AndroidManagementService.Scope.Androidmanagement),
                    ApplicationName = "BluProductsApp"
                });


                //Fetch client information from GCP
                dynamic name = "";
                dynamic email = "";
                if (User.Identity is ClaimsIdentity claimsIdentity)
                {
                    var listk = claimsIdentity.Claims.Select(x => new { x.Type, x.Value }).ToList();
                    name = listk[3].Value;
                    email = User.FindFirstValue(ClaimTypes.Email);
                }

                //var enterpriseRes = _iEmmMapper.GetEnterprises().Where(x=> x.ClientEmail == email);
                //if(enterpriseRes!= null)
                //{
                //    TempData["MsgSignupFailed"] = "There is already an Enterprise exist. Please try with a different mail to add a new Enterprise.";
                //    return View(enterpriseModel);
                //}
                #endregion

                dynamic response = "";
                string enterpriseToken = Convert.ToString(TempData["EnterpriseToken"]) ?? null;
                if (string.IsNullOrEmpty(enterpriseToken))
                {
                    //create signup url
                    var signupData = service.SignupUrls.Create();
                    signupData.AccessToken = cred.UnderlyingCredential.GetAccessTokenForRequestAsync().Result;
                    signupData.ProjectId = ProjectId;
                    signupData.CallbackUrl = _iConfiguration.GetValue<string>("AppSetting:CallBackURL");
                    response = signupData.Execute();

                    //assign signup data to vmodel
                    enterpriseModel.SignupUrlName = response.Name;
                    enterpriseModel.SignupUrlURL = response.Url;

                    //store signupurl name in session
                    HttpContext.Session.SetString("SignupUrlName", Convert.ToString(enterpriseModel.SignupUrlName));
                    

                    //assign client info to model
                    enterpriseModel.ClientName = name;
                    enterpriseModel.ClientEmail = email;

                    //insert data into database
                    var result = _iEmmMapper.CreateUpdateEnterprise(enterpriseModel);
                }
                else
                {
                    //create enterprise
                    var enterpriseData = service.Enterprises.Create(new Enterprise());
                    enterpriseData.AccessToken = cred.UnderlyingCredential.GetAccessTokenForRequestAsync().Result;
                    enterpriseData.ProjectId = ProjectId;
                    enterpriseData.SignupUrlName = HttpContext.Session.GetString("SignupUrlName");
                    enterpriseData.EnterpriseToken = Convert.ToString(TempData["EnterpriseToken"]) ?? null;
                    var enterpriseResponse = enterpriseData.Execute();
                    enterpriseModel.Name = enterpriseResponse.Name;
                    enterpriseModel.EnterpriseToken = enterpriseData.EnterpriseToken;


                    //assign client info to vmodel
                    enterpriseModel.ClientName = name;
                    enterpriseModel.ClientEmail = email;

                    //fetch enterprise from db
                    var resultEnterprise = _iEmmMapper.GetEnterprises();
                    if (resultEnterprise != null)
                    {
                        foreach (var enterprise in resultEnterprise)
                        {
        
                        //create default policies for [fixed enterprise]
                        string policyName = enterpriseModel.Name + "/policies/" + PolicyId;
                                

                        //set a default policy with all latest changes
                        var appliedPolicyData = service.Enterprises.Policies.Patch(DefaultPolicies(commonPolicies), policyName).Execute();
                        enterpriseModel.PolicyName = policyName;

                            //create User
                            var user = new User
                            {
                                AccountIdentifier = Guid.NewGuid().ToString()
                            };

                            //create enrollmentToken with a with policy name & assign created user
                            EnrollmentToken token = new DemoEnrollmentToken().SetPolicyName(PolicyId).SetUser(user.AccountIdentifier).SetDuration("2592000s");
                            var tokenResponse = service.Enterprises.EnrollmentTokens.Create(token, enterpriseModel.Name).Execute();
                            var eToken = tokenResponse.Value;
                            enterpriseModel.EnrollmentToken = eToken;
                        }
                    }

                    //insert/update data into database
                    var result = _iEmmMapper.CreateUpdateEnterprise(enterpriseModel);
                }
                return View(enterpriseModel);
            }
            catch (Google.GoogleApiException gex)
            {
                string msgErr = "Error in " + this.GetType().ToString();
                _loggerManager.LogError($"{msgErr}{gex.Message}");
                TempData["Failure"] = "There is some technical issue. Please try again.";
                return View(new EnterpriseDto());
            }
            catch (Exception ex)
            {
                string msgErr = "Error in " + this.GetType().ToString();
                _loggerManager.LogError($"{msgErr}{ex.Message}");
                return View(new EnterpriseDto());
            }
        }

Enterprse Get Method:

[HttpGet]
        public IActionResult CreateEnterprise(EnterpriseDto enterpriseDto, string enterpriseToken)
        {
            try
            {
                TempData["EnterpriseToken"] = string.Empty;
                if (!string.IsNullOrEmpty(enterpriseToken))
                {
                    TempData["EnterpriseToken"] = Convert.ToString(HttpContext.Request.Query["enterpriseToken"]);
                    TempData["MsgEnterpriseToken"] = "Google Play signup successful.";
                }
                //
                var result = _iEmmMapper.GetEnterprises();
                if (result != null)
                {
                    foreach (var enterprise in result)
                    {
                        enterpriseDto.Name = enterprise.Name;
                        enterpriseDto.EnrollmentToken = enterprise.EnrollmentToken;
                        enterpriseDto.EnrollmentTokenExpiryDate = enterprise.ModifiedDate.AddMonths(1).ToShortDateString();
                    }
                }
                //
                return View(enterpriseDto);
            }
            catch (Exception ex)
            {
                _loggerManager.LogError($"Something went wrong inside CreateEnterprise get action: {ex.Message}");
                return View(enterpriseDto);
            }
        }

CreateEnterprise.cshtml page:

 <form id='fCreateEnterprise' asp-action="CreateEnterprise">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                @if (Model != null)
                {
                    <div class="row" style="display:none;">
                        <div class="col-md-6">
                            <label [email protected] class="control-label mt-2"></label>
                            <input [email protected] class="form-control" readonly="readonly" />
                        </div>
                        <div class="col-md-6">
                            <label [email protected] class="control-label mt-2"></label>
                            <input [email protected] class="form-control" readonly="readonly" />
                        </div>
                    </div>
                }
                <div class="col-md-4 mt-4 offset-4">
                    <input type="submit" id="btnVerify" value="Verify" class="btn btn-success text-center" />
                    @*<input type="button" id="btnVerification" value="Verification" class="btn btn-success text-center" />*@
                    @if (Model.SignupUrlURL != null)
                    {
                        <a href="@Model.SignupUrlURL" target="_blank" class="btn btn-secondary text-center">Complete Signup</a>
                    }
                    else
                    {
                        <a href="#" target="_blank" class="btn btn-secondary text-center">Complete Signup</a>
                    }
                    <input type="submit" value="Create Enterprise" class="btn btn-primary text-center" />
                </div>
            </form>

Upvotes: 0

Views: 590

Answers (1)

Danica
Danica

Reputation: 191

Enterprises created on AM API can only be managed by a unique service account registered with your Cloud project via Cloud IAM. For existing EMM partners this is the recommended method of authentication. As you mentioned having multiple enterprises, please note that you can manage multiple enterprises using this authentication method.

Alternatively, you could also consider using Customer-managed enterprises. A quickstart guide is also available as a reference for enrolling an enterprise, creating a policy, and provisioning a device.

Upvotes: 4

Related Questions