-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Start on OIDC Auth Provider for 2016
Needs: LogonMethod and OidcLogon.aspx page to be completed
- Loading branch information
Ryan Posener
committed
Apr 3, 2018
1 parent
e24f2c6
commit 85cfbad
Showing
19 changed files
with
1,742 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio 15 | ||
VisualStudioVersion = 15.0.27428.2015 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SSRS.OpenIDConnect.Security", "src\SSRS.OpenIDConnect.Security\SSRS.OpenIDConnect.Security.csproj", "{F9ACAA61-EC47-47DC-8592-64C79E3B309F}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SSRS.OpenIDConnect.Security.Tests", "test\SSRS.OpenIDConnect.Security.Tests\SSRS.OpenIDConnect.Security.Tests.csproj", "{71657227-1D08-42C6-88AD-AAD05BDF0BBA}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{F9ACAA61-EC47-47DC-8592-64C79E3B309F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{F9ACAA61-EC47-47DC-8592-64C79E3B309F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{F9ACAA61-EC47-47DC-8592-64C79E3B309F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{F9ACAA61-EC47-47DC-8592-64C79E3B309F}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{71657227-1D08-42C6-88AD-AAD05BDF0BBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{71657227-1D08-42C6-88AD-AAD05BDF0BBA}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{71657227-1D08-42C6-88AD-AAD05BDF0BBA}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{71657227-1D08-42C6-88AD-AAD05BDF0BBA}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {A067B11E-804C-4700-B7FA-7C34045DBCBD} | ||
EndGlobalSection | ||
EndGlobal |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
using IdentityModel; | ||
using IdentityModel.Client; | ||
using Microsoft.IdentityModel.Tokens; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IdentityModel.Tokens.Jwt; | ||
using System.Linq; | ||
using System.Runtime.Caching; | ||
using System.Security.Claims; | ||
using System.Security.Cryptography; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace SSRS.OpenIDConnect.Security.OIDC | ||
{ | ||
/// <summary> | ||
/// Helper Class to Work with Open ID Connect Protocol | ||
/// </summary> | ||
public class OIDCUtilities | ||
{ | ||
const string CACHE_DISCO = "OIDC.CACHE.DISCO"; | ||
|
||
|
||
// Connection Details for our API | ||
private Uri m_authUri; | ||
|
||
/// <summary> | ||
/// Constructs a Helper Class to Query the PE Api | ||
/// </summary> | ||
/// <param name="Url">URL to a PE instance</param> | ||
public OIDCUtilities(Uri authUri) | ||
{ | ||
m_authUri = authUri; | ||
} | ||
|
||
/// <summary> | ||
/// Returns the Open ID Connect Bearer Discovery Information | ||
/// </summary> | ||
/// <returns></returns> | ||
public DiscoveryResponse DiscoverOidcSettings() | ||
{ | ||
if (!MemoryCache.Default.Contains(CACHE_DISCO)) | ||
{ | ||
var disco = DiscoveryClient.GetAsync(m_authUri.AbsoluteUri); | ||
MemoryCache.Default.Add(CACHE_DISCO, disco.Result, DateTimeOffset.Now.AddHours(2)); | ||
} | ||
|
||
return MemoryCache.Default[CACHE_DISCO] as DiscoveryResponse; | ||
} | ||
|
||
/// <summary> | ||
/// Builds a Login Uri to redirect the user for login | ||
/// </summary> | ||
/// <returns></returns> | ||
public string BuildAuthorizeUrl(string state) | ||
{ | ||
var nonce = Guid.NewGuid().ToString("N"); | ||
MemoryCache.Default.Add(nonce, nonce, DateTimeOffset.Now.AddMinutes(10)); | ||
var disco = DiscoverOidcSettings(); | ||
var authorizeUrl = new RequestUrl(disco.AuthorizeEndpoint).CreateAuthorizeUrl( | ||
clientId: "pe.app", | ||
responseType: "id_token", | ||
scope: "openid profile", | ||
redirectUri: "http://localhost:44078/home/callback", | ||
state: state, | ||
nonce: nonce, | ||
responseMode: "form_post"); | ||
|
||
return authorizeUrl; | ||
} | ||
|
||
/// <summary> | ||
/// Validates an Identity Token | ||
/// </summary> | ||
/// <param name="idToken">The Received ID Token</param> | ||
/// <returns></returns> | ||
public ClaimsPrincipal ValidateIdentityToken(string idToken) | ||
{ | ||
var user = ValidateJwt(idToken); | ||
|
||
var nonce = user.FindFirst("nonce")?.Value ?? ""; | ||
if (MemoryCache.Default[nonce] as string != nonce) | ||
throw new Exception("invalid nonce"); | ||
|
||
return user; | ||
} | ||
|
||
/// <summary> | ||
/// Validates a JWT token | ||
/// </summary> | ||
/// <param name="jwt">the JWT Token</param> | ||
/// <returns></returns> | ||
private ClaimsPrincipal ValidateJwt(string jwt) | ||
{ | ||
// read discovery document to find issuer and key material | ||
var disco = DiscoverOidcSettings(); | ||
|
||
var keys = new List<SecurityKey>(); | ||
foreach (var webKey in disco.KeySet.Keys) | ||
{ | ||
var e = Base64Url.Decode(webKey.E); | ||
var n = Base64Url.Decode(webKey.N); | ||
|
||
var key = new RsaSecurityKey(new RSAParameters { Exponent = e, Modulus = n }) | ||
{ | ||
KeyId = webKey.Kid | ||
}; | ||
|
||
keys.Add(key); | ||
} | ||
|
||
var parameters = new TokenValidationParameters | ||
{ | ||
ValidIssuer = disco.Issuer, | ||
ValidAudience = "pe.app", | ||
IssuerSigningKeys = keys, | ||
|
||
NameClaimType = JwtClaimTypes.Name, | ||
RoleClaimType = JwtClaimTypes.Role | ||
}; | ||
|
||
var handler = new JwtSecurityTokenHandler(); | ||
handler.InboundClaimTypeMap.Clear(); | ||
|
||
var user = handler.ValidateToken(jwt, parameters, out var _); | ||
return user; | ||
} | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<%@ Page language="c#" Codebehind="oidc.aspx.cs" AutoEventWireup="false" Inherits="SSRS.OpenIDConnect.Security.OidcLogon, SSRS.OpenIDConnect.Security" Culture="auto" UICulture="auto" %> | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<title>Open ID Connect Authentication Page</title> | ||
</head> | ||
<body style="height:100vh;display:grid;"> | ||
<h2 style="margin:auto;">Logging in with Open ID Connect...</h2> | ||
</body> | ||
</html> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.Web.Security; | ||
|
||
namespace SSRS.OpenIDConnect.Security | ||
{ | ||
public class OidcLogon : System.Web.UI.Page | ||
{ | ||
private void Page_Load(object sender, System.EventArgs e) | ||
{ | ||
if (Request.HttpMethod.Equals("post", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
FormsAuthentication.RedirectFromLoginPage( | ||
"AzureAD\\RyanPosener", false); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.