Skip to content

Commit

Permalink
Start on OIDC Auth Provider for 2016
Browse files Browse the repository at this point in the history
Needs: LogonMethod and OidcLogon.aspx page to be completed
  • Loading branch information
Ryan Posener committed Apr 3, 2018
1 parent e24f2c6 commit 85cfbad
Show file tree
Hide file tree
Showing 19 changed files with 1,742 additions and 0 deletions.
31 changes: 31 additions & 0 deletions SSRS.Security.sln
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
129 changes: 129 additions & 0 deletions src/SSRS.OpenIDConnect.Security/OIDC/OIDCUtilities.cs
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;
}
}
}
11 changes: 11 additions & 0 deletions src/SSRS.OpenIDConnect.Security/OidcLogon.aspx
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>
21 changes: 21 additions & 0 deletions src/SSRS.OpenIDConnect.Security/OidcLogon.aspx.cs
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);
}
}
}
}
Loading

0 comments on commit 85cfbad

Please sign in to comment.