Skip to content

Instantly share code, notes, and snippets.

@nzpcmad
Created March 21, 2016 22:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nzpcmad/28f8d685314c348a1557 to your computer and use it in GitHub Desktop.
Save nzpcmad/28f8d685314c348a1557 to your computer and use it in GitHub Desktop.
WebApp-WebAPI-OpenIDConnect-DotNet-TP4-Git - Sample for ADFS 4.0 - Server 2016
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
/*app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Audience = ConfigurationManager.AppSettings["ida:Audience"],
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
});*/
// Added ADFS 4.0 code
app.UseActiveDirectoryFederationServicesBearerAuthentication(
new ActiveDirectoryFederationServicesBearerAuthenticationOptions
{
//Audience = "https://myservices/myAPI",
Audience = "https://localhost:44321/",
MetadataEndpoint = "https://my-adfs/FederationMetadata/2007-06/FederationMetadata.xml"
});
}
}
<!--Added ADFS 4.0 code-->
<!--<add key="ida:Tenant" value="[Enter tenant name, e.g. contoso.onmicrosoft.com]" />
<add key="ida:Audience" value="[Enter App ID URI of TodoListService, e.g. https://contoso.onmicrosoft.com/TodoListService]" />-->
//----------------------------------------------------------------------------------------------
// Copyright 2014 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//----------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
// The following using statements were added for this sample.
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OpenIdConnect;
using Microsoft.Owin.Security.Cookies;
using TodoListWebApp.Utils;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Claims;
using System.Configuration;
using System.Globalization;
namespace TodoListWebApp.Controllers
{
public class AccountController : Controller
{
public void SignIn()
{
// Send an OpenID Connect sign-in request.
if (!Request.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}
public void SignOut()
{
// Added ADFS 4.0 code
/*// Remove all cache entries for this user and send an OpenID Connect sign-out request.
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID));
authContext.TokenCache.Clear();
HttpContext.GetOwinContext().Authentication.SignOut(
OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);*/
}
}
}
// Added ADFS 4.0 code
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string appKey = ConfigurationManager.AppSettings["ida:AppKey"];
private static string metadataAddress = ConfigurationManager.AppSettings["ida:ADFSDiscoveryDoc"];
private static string postLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"];
// Added ADFS 4.0 code
//public static readonly string Authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
public static readonly string Authority = "https://my-adfs/adfs/";
public static string accessToken = "";
// Added ADFS 4.0 code
// This is the resource ID of the AAD Graph API. We'll need this to request a token to call the Graph API.
//string graphResourceId = ConfigurationManager.AppSettings["ida:GraphResourceId"];
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
/*ClientId = clientId,
Authority = Authority,
PostLogoutRedirectUri = postLogoutRedirectUri,*/
// Added ADFS 4.0 code
ClientId = clientId,
MetadataAddress = metadataAddress,
RedirectUri = postLogoutRedirectUri,
//PostLogoutRedirectUri = postLogoutRedirectUri,
Resource = "https://localhost:44321/",
Scope = "user_impersonation",
Notifications = new OpenIdConnectAuthenticationNotifications()
{
// Added ADFS 4.0 code
//
// If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
//
/*AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(clientId, appKey);
string userObjectID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceId);
return Task.FromResult(0);
},*/
// Added ADFS 4.0 code
AuthorizationCodeReceived = context =>
{
string code = context.Code;
AuthenticationContext ac = new AuthenticationContext("https://my-adfs/adfs/", false);
AuthenticationResult ar = ac.AcquireTokenByAuthorizationCode
(
code,
new Uri("https://localhost:44322/"),
new ClientCredential(clientId, appKey),
//"https://myservices/myAPI");
"https://localhost:44321/"
);
// Pretend we have a token store
accessToken = ar.AccessToken;
string callOutcome = string.Empty;
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ar.AccessToken);
HttpResponseMessage response = httpClient.GetAsync("https://localhost:44321/api/values").Result;
if (response.IsSuccessStatusCode)
{
callOutcome = response.Content.ReadAsStringAsync().Result;
}
return Task.FromResult(0);
},
AuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("/Home/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
}
}
});
//----------------------------------------------------------------------------------------------
// Copyright 2014 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//----------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
// The following using statements were added for this sample.
using System.Configuration;
using System.Threading.Tasks;
using System.Security.Claims;
using TodoListWebApp.Utils;
using TodoListWebApp.Models;
using Microsoft.Owin.Security.OpenIdConnect;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
namespace TodoListWebApp.Controllers
{
[Authorize]
public class TodoListController : Controller
{
private string todoListResourceId = ConfigurationManager.AppSettings["todo:TodoListResourceId"];
private string todoListBaseAddress = ConfigurationManager.AppSettings["todo:TodoListBaseAddress"];
private const string TenantIdClaimType = "http://schemas.microsoft.com/identity/claims/tenantid";
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string appKey = ConfigurationManager.AppSettings["ida:AppKey"];
//
// GET: /TodoList/
public async Task<ActionResult> Index()
{
AuthenticationResult result = null;
List<TodoItem> itemList = new List<TodoItem>();
try
{
// Added ADFS 4.0 code
/*string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, false);
ClientCredential credential = new ClientCredential(clientId, appKey);
result = authContext.AcquireTokenSilent(todoListResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));*/
//
// Retrieve the user's To Do List.
//
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, todoListBaseAddress + "/api/todolist");
// Added ADFS 4.0 code
//request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Startup.accessToken);
HttpResponseMessage response = await client.SendAsync(request);
//
// Return the To Do List in the view.
//
if (response.IsSuccessStatusCode)
{
List<Dictionary<String, String>> responseElements = new List<Dictionary<String, String>>();
JsonSerializerSettings settings = new JsonSerializerSettings();
String responseString = await response.Content.ReadAsStringAsync();
responseElements = JsonConvert.DeserializeObject<List<Dictionary<String, String>>>(responseString, settings);
foreach (Dictionary<String, String> responseElement in responseElements)
{
TodoItem newItem = new TodoItem();
newItem.Title = responseElement["Title"];
newItem.Owner = responseElement["Owner"];
itemList.Add(newItem);
}
return View(itemList);
}
else
{
//
// If the call failed with access denied, then drop the current access token from the cache,
// and show the user an error indicating they might need to sign-in again.
//
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
// Added ADFS 4.0 code
/*var todoTokens = authContext.TokenCache.ReadItems().Where(a => a.Resource == todoListResourceId);
foreach (TokenCacheItem tci in todoTokens)
authContext.TokenCache.DeleteItem(tci); */
ViewBag.ErrorMessage = "UnexpectedError";
TodoItem newItem = new TodoItem();
newItem.Title = "(No items in list)";
itemList.Add(newItem);
return View(itemList);
}
}
}
catch (Exception ee)
{
if (Request.QueryString["reauth"] == "True")
{
//
// Send an OpenID Connect sign-in request to get a new set of tokens.
// If the user still has a valid session with Azure AD, they will not be prompted for their credentials.
// The OpenID Connect middleware will return to this controller after the sign-in response has been handled.
//
HttpContext.GetOwinContext().Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
//
// The user needs to re-authorize. Show them a message to that effect.
//
TodoItem newItem = new TodoItem();
newItem.Title = "(Sign-in required to view to do list.)";
itemList.Add(newItem);
ViewBag.ErrorMessage = "AuthorizationRequired";
return View(itemList);
}
//
// If the call failed for any other reason, show the user an error.
//
return View("Error");
}
[HttpPost]
public async Task<ActionResult> Index(string item)
{
if (ModelState.IsValid)
{
//
// Retrieve the user's tenantID and access token since they are parameters used to call the To Do service.
//
AuthenticationResult result = null;
List<TodoItem> itemList = new List<TodoItem>();
try
{
// Added ADFS 4.0 code
/*string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID));
ClientCredential credential = new ClientCredential(clientId, appKey);
result = authContext.AcquireTokenSilent(todoListResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));*/
// Forms encode todo item, to POST to the todo list web api.
HttpContent content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("Title", item) });
//
// Add the item to user's To Do List.
//
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, todoListBaseAddress + "/api/todolist");
// Added ADFS 4.0 code
//request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Startup.accessToken);
request.Content = content;
HttpResponseMessage response = await client.SendAsync(request);
//
// Return the To Do List in the view.
//
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
//
// If the call failed with access denied, then drop the current access token from the cache,
// and show the user an error indicating they might need to sign-in again.
//
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
// Added ADFS 4.0 code
/*var todoTokens = authContext.TokenCache.ReadItems().Where(a => a.Resource == todoListResourceId);
foreach (TokenCacheItem tci in todoTokens)
authContext.TokenCache.DeleteItem(tci); */
ViewBag.ErrorMessage = "UnexpectedError";
TodoItem newItem = new TodoItem();
newItem.Title = "(No items in list)";
itemList.Add(newItem);
return View(newItem);
}
}
}
catch (Exception ee)// TODO: verify that the exception is 'silentauth failed'
{
//
// The user needs to re-authorize. Show them a message to that effect.
//
TodoItem newItem = new TodoItem();
newItem.Title = "(No items in list)";
itemList.Add(newItem);
ViewBag.ErrorMessage = "AuthorizationRequired";
return View(itemList);
}
//
// If the call failed for any other reason, show the user an error.
//
return View("Error");
}
return View("Error");
}
}
}
<!--Added ADFS 4.0 code-->
<add key="ida:ClientId" value="be28158b-...3f682ed547a" />
<add key="ida:AppKey" value="Um6fYoWZwWc...dxoR6ixVnCLCJIbIvnkblBNmso" />
<add key="ida:ADFSDiscoveryDoc" value="https://my-adfs/adfs/.well-known/openid-configuration" />
<add key="ida:PostLogoutRedirectUri" value="https://localhost:44322/" />
<add key="todo:TodoListResourceid" value="https://localhost:44321" />
<add key="todo:TodoListBaseAddress" value="https://localhost:44321" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment