/* ======================================================================== * Copyright (c) 2005-2026 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Opc.Ua.Identity { /// /// Static JWT bearer for tests, /// smoke flows, and callers that obtain the token out-of-band. /// public sealed class JwtBearerAccessTokenProvider : IAccessTokenProvider { /// /// Creates a provider for a pre-supplied JWT payload. /// public JwtBearerAccessTokenProvider( string authorityUri, byte[] tokenBytes, DateTime expiresAt, string displayName = "") : this(authorityUri, tokenBytes, expiresAt, displayName, null) { } /// /// Creates a provider for a pre-supplied JWT payload with a /// caller-supplied for expiry checks. /// public JwtBearerAccessTokenProvider( string authorityUri, byte[] tokenBytes, DateTime expiresAt, string displayName, TimeProvider? timeProvider) { if (tokenBytes == null) { throw new ArgumentNullException(nameof(tokenBytes)); } AuthorityUri = authorityUri ?? throw new ArgumentNullException(nameof(authorityUri)); m_tokenBytes = (byte[])tokenBytes.Clone(); m_expiresAt = expiresAt; m_displayName = displayName ?? string.Empty; m_timeProvider = timeProvider ?? TimeProvider.System; } /// /// Creates a provider by UTF-8 encoding a compact JWT string. /// public static JwtBearerAccessTokenProvider FromJwtString( string authorityUri, string jwt, DateTime expiresAt, string displayName = "") { return FromJwtString(authorityUri, jwt, expiresAt, displayName, null); } /// /// Creates a provider by UTF-8 encoding a compact JWT string, /// using the supplied for expiry checks. /// public static JwtBearerAccessTokenProvider FromJwtString( string authorityUri, string jwt, DateTime expiresAt, string displayName, TimeProvider? timeProvider) { if (jwt == null) { throw new ArgumentNullException(nameof(jwt)); } return new JwtBearerAccessTokenProvider( authorityUri, Encoding.UTF8.GetBytes(jwt), expiresAt, displayName, timeProvider); } /// public string AuthorityUri { get; } /// public ValueTask AcquireAsync( AuthorizationServerMetadata metadata, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); if (m_expiresAt <= m_timeProvider.GetUtcNow().UtcDateTime) { throw ServiceResultException.Create( StatusCodes.BadIdentityTokenRejected, "Token has expired."); } #pragma warning disable CA2000 // Ownership transfers to caller; TODO: remove when analyzer models ValueTask ownership. return new ValueTask(CreateAccessToken()); #pragma warning restore CA2000 } private AccessToken CreateAccessToken() { return new AccessToken( Profiles.JwtUserToken, (byte[])m_tokenBytes.Clone(), m_expiresAt, m_displayName); } private readonly byte[] m_tokenBytes; private readonly DateTime m_expiresAt; private readonly string m_displayName; private readonly TimeProvider m_timeProvider; } }