using System;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Security.Authentication;
using Serilog;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc;
using OnlineBankingAuth.Tokens;
using Landmark.OLA.Models.OnlineBanking;
using Landmark.OLA.Application.Common.Security;
using Landmark.OLA.Models.Core;
using OnlineBankingAuth.Parsers;
using OnlineBankingAuth.Services;
namespace Landmark.OLA.Application.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SamlAssertionConsumerController : ControllerBase
{
private readonly IDigitalInsightVendorClient _diVendor;
private readonly ITokenService _tokenService;
public SamlAssertionConsumerController
(
IDigitalInsightVendorClient diVendor,
ITokenService tokenService
)
{
_diVendor = diVendor;
_tokenService = tokenService;
}
///
/// Use to refer a user to the application with a valid SAML assertion
///
///
/// Returns an application redirect, adding in a SAML assertion via a JWT in a secure http-only cookie.
/// Cookies: Set a standard pair of authentication and authorization cookies.
/// Security: Passed document must include a valid, signed SAML assertion, provides member authentication.
///
// POST: api/SAMLAssertionConsumer
[HttpPost]
[ProducesResponseType(403)]
[ProducesResponseType(401)]
[ProducesResponseType(201)]
[ProducesResponseType(typeof(ModelStateDictionary), 401)]
public async Task Post([FromForm] SAMLMessaging document)
{
try
{
var decodedString = Encoding.UTF8.GetString(Convert.FromBase64String(document.SAMLResponse));
var parsedXml = XElement.Parse(decodedString);
var xmlDocument = new XmlDocument
{
PreserveWhitespace = true
};
xmlDocument.Load(parsedXml.CreateReader());
// @TODO: Should catch error here, move element query to static service #1400b
var x509Payload = (XmlElement)xmlDocument.GetElementsByTagName("ds:X509Certificate")[0];
var vendorCertMatches = _diVendor.ValidateDIPublicKey(x509Payload);
if (!vendorCertMatches)
{
throw new AuthenticationException("The vendor's public certificate did not match! ");
}
var assertion = _diVendor.GetSAMLPayload(xmlDocument);
// Check that assertion is still valid
var datesValid = _diVendor.ValidateTimeStamp(assertion);
if (!datesValid)
{
throw new AuthenticationException("The Authentication has expired!");
}
var obToken = new OnlineBankingToken(assertion, null, true)
{
IsTwoFactor = true
};
obToken.IndividualID = obToken.MemberID;
AssignTokens(obToken);
HttpContext.Response.Redirect(_diVendor.GetSuccessRedirectUrl());
}
catch (Exception ex)
{
Log.Error(ex, $"Failure to validate SAML in {GetType().Name}");
HttpContext.Response.Redirect(_diVendor.GetFailureRedirectUrl(ex.Message));
}
}
private void AssignTokens(OnlineBankingToken obToken)
{
var meta = new MemberMeta
{
IsTwoFactor = obToken.IsTwoFactor,
IsMember = (obToken.MemberID != null),
IsIndividual = (obToken.IndividualID != null)
};
var privateToken = _tokenService.CreateOnlineBankingJWT(obToken);
var publicToken = _tokenService.CreateAuthMetaToken(meta);
CookieService.SetAuthenticationCookie(HttpContext.Response.Cookies, privateToken);
CookieService.SetAuthorizationCookie(HttpContext.Response.Cookies, publicToken);
}
///
/// Use to create an empty cookie session
///
///
/// Returns a pair of empty authorization and authentication cookies.
/// Cookies: Sets empty Authentication and Authorization cookies.
/// Security: None required or provided.
///
[HttpGet("InitSession")]
[ProducesResponseType(200)]
public IActionResult Get()
{
var obToken = new OnlineBankingToken
{
MemberID = null, IndividualID = null, FI_ID = "0", IsTwoFactor = false
};
AssignTokens(obToken);
return Ok();
}
///
/// Use to create a cookie session with credentials
///
///
/// Returns a pair of authorization and authentication cookies when provided with valid credentials.
/// Cookies: Sets Authentication and Authorization cookies.
/// Security: Require.
///
[HttpPost("Authenticate")]
[ProducesResponseType(403)]
[ProducesResponseType(201)]
[ProducesResponseType(typeof(ModelStateDictionary), 401)]
public async Task