Created
March 21, 2016 22:51
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | |
}); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--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]" />--> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//---------------------------------------------------------------------------------------------- | |
// 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);*/ | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} | |
} | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//---------------------------------------------------------------------------------------------- | |
// 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"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--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
http://nzpcmad.blogspot.co.nz/2016/03/adfs-webapp-and-web-api-on-server-2016.html