//
        // GET: /UserProfile/
        public async Task <ActionResult> Index(string authError)
        {
            UserProfile profile = new UserProfile();

            string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier").Value;
            // Always setup the OAuth /authorize URI to use
            Uri    redirectUri = new Uri(Request.Url.GetLeftPart(UriPartial.Authority).ToString() + "/OAuth");
            string state       = GenerateState(userObjectID, Request.Url.ToString());
            string msoauthUri  = string.Format("{0}/oauth2/authorize?resource={1}&client_id={2}&response_type=code&redirect_uri={3}&state={4}",
                                               Startup.Authority, Url.Encode(Startup.graphResourceId), Startup.clientId, Url.Encode(redirectUri.ToString()), state);

            ViewBag.AuthorizationUrl = msoauthUri;
            // Check local OAuthDataStore to see if we have previously cached OAuth bearer tokens for this user.
            IEnumerable <OAuthTokenSet> query =
                from OAuthTokenSet in model.OAuthTokens where OAuthTokenSet.userId == userObjectID && OAuthTokenSet.state == state select OAuthTokenSet;

            if (query.GetEnumerator().MoveNext() == false)
            {
                authError = "AuthorizationRequired";
            }
            else
            {
                OAuthTokenSet usertokens = query.First();
                profile.AccessToken       = usertokens.accessToken;
                profile.RefreshToken      = usertokens.refreshToken;
                profile.AccessTokenExpiry = usertokens.accessTokenExpiry;
                authError = null;
            }



            // Leaving this chunk of code alone, it generates the URL that the user will be redirected to when they
            // opt to sign in again. Per OAuth2 flow, this redirect will send the user to MS OAuth endpoint where they
            // will enter their creds. The resulting Authorization code is then used to get tokens. The OAuthController
            // will redirect users back to this controller, where we should be able to continue because the user completed
            // OAuth ok.
            if (authError != null)
            {
                profile              = new UserProfile();
                profile.DisplayName  = " ";
                profile.GivenName    = " ";
                profile.Surname      = " ";
                ViewBag.ErrorMessage = authError;
                return(View(profile));
            }

            OAuthTokenSet token = query.First();

            try
            {
                //
                // Call the Graph API and retrieve the user's profile.
                //
                string requestUrl = String.Format(
                    CultureInfo.InvariantCulture,
                    Startup.graphUserUrl,
                    HttpUtility.UrlEncode(Startup.tenant));
                HttpClient         client  = new HttpClient();
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.accessToken);
                HttpResponseMessage response = await client.SendAsync(request);

                //
                // Return the user's profile in the view.
                //
                if (response.IsSuccessStatusCode)
                {
                    string responseString = await response.Content.ReadAsStringAsync();

                    UserProfile tmp = JsonConvert.DeserializeObject <UserProfile>(responseString);
                    // Copy over only the fields recevied from GraphAPI
                    profile.DisplayName = tmp.DisplayName;
                    profile.GivenName   = tmp.GivenName;
                    profile.Surname     = tmp.Surname;
                    return(View(profile));
                }
                else if (response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    //
                    // If the call failed, then drop the current access token and show the user an error indicating they might need to sign-in again.

                    model.OAuthTokens.RemoveRange(model.OAuthTokens);
                    model.SaveChanges();



                    profile              = new UserProfile();
                    profile.DisplayName  = " ";
                    profile.GivenName    = " ";
                    profile.Surname      = " ";
                    ViewBag.ErrorMessage = "AuthorizationRequired";
                    return(View(profile));
                }
                else
                {
                    ViewBag.ErrorMessage = "Error Calling Graph API.";
                    return(View("Error"));
                }
            }
            catch
            {
                ViewBag.ErrorMessage = "Error Calling Graph API.";
                return(View("Error"));
            }
        }
Example #2
0
        //
        // This method will be invoked as a call-back from an authentication service (e.g., https://login.microsoftonline.com/).
        // It is not intended to be called directly, only as a redirect from the authorization request in UserProfileController.
        // On completion, the method will cache the refresh token and access tokens, and redirect to the URL
        //     specified in the state parameter.
        //
        public async Task <ActionResult> Index(string code, string error, string error_description, string resource, string state)
        {
            string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier").Value;

            // NOTE: In production, OAuth must be done over a secure HTTPS connection.
            if (Request.Url.Scheme != "https" && !Request.Url.IsLoopback)
            {
                return(View("Error"));
            }

            // Ensure there is a state value on the response.  If there is none, stop OAuth processing and display an error.
            if (state == null)
            {
                ViewBag.ErrorMessage = "Error Generating State.";
                return(View("Error"));
            }

            // Handle errors from the OAuth response, if any.  If there are errors, stop OAuth processing and display an error.
            if (error != null)
            {
                return(View("Error"));
            }

            string redirectUri = ValidateState(state, userObjectID);

            if (redirectUri == null)
            {
                ViewBag.ErrorMessage = "Error Validating State.";
                return(View("Error"));
            }

            // Redeem the authorization code from the response for an access token and refresh token.
            // When this code completes, the user is redirected back to /UserProfile so the UserProfileController.Index
            // method can then fetch the tokens and use them in subsequent calls.
            try
            {
                // Replace this with code to get the access tokens manually
                string         dest = "https://login.microsoftonline.com/b3aa98fb-8679-40e4-a942-6047017aa1a4/oauth2/token";
                HttpWebRequest req  = (HttpWebRequest)WebRequest.Create(dest);
                req.Method      = "POST";
                req.ContentType = "application/x-www-form-urlencoded";
                string postData = String.Format("grant_type=authorization_code&client_id={0}&code={1}&redirect_uri={2}&client_secret={3}&resource={4}",
                                                Startup.clientId, code, new Uri(Request.Url.GetLeftPart(UriPartial.Path)), Startup.appKey, resource);
                System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                byte[] bytes = encoding.GetBytes(postData);
                req.ContentLength = bytes.Length;
                Stream nStream = req.GetRequestStream();
                nStream.Write(bytes, 0, bytes.Length);
                nStream.Close();
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                System.Runtime.Serialization.Json.DataContractJsonSerializer json = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(OAuthTokenResponse));
                OAuthTokenResponse          recvtoken    = json.ReadObject(resp.GetResponseStream()) as OAuthTokenResponse;
                OAuthDataStore              model        = new OAuthDataStore();
                string                      encodedState = Url.Encode(state);
                IEnumerable <OAuthTokenSet> query        =
                    from OAuthTokenSet in model.OAuthTokens where OAuthTokenSet.state == encodedState select OAuthTokenSet;
                OAuthTokenSet token = query.First();
                token.accessToken       = recvtoken.access_token;
                token.tokenType         = recvtoken.token_type;
                token.refreshToken      = recvtoken.refresh_token;
                token.userId            = userObjectID;
                token.state             = state;
                token.accessTokenExpiry = DateTime.Now.AddSeconds(Convert.ToDouble(recvtoken.expires_in)).ToUniversalTime().ToString(DateTimeFormatInfo.CurrentInfo.UniversalSortableDateTimePattern);

                try
                {
                    model.SaveChanges();
                }
                catch (Exception e)
                {
                    throw;
                }
                return(Redirect(redirectUri));
            }
            catch (Exception e)
            {
                return(Redirect("/UserProfile/Index?authError=token"));
            }
        }