/* ======================================================================== * 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.Threading; using System.Threading.Tasks; using Opc.Ua.Security.Certificates; namespace Opc.Ua.Identity { /// /// Outcome of an authentication attempt by an /// . /// public enum AuthenticationOutcome { /// /// The authenticator does not handle the supplied token type / /// profile and the registry should ask the next authenticator /// (or fall back to the legacy /// SessionManager.ImpersonateUser event). /// NotHandled, /// /// The token was accepted; /// is populated. /// Accepted, /// /// The token was rejected; /// describes the /// rejection reason and is reported back to the client. /// Rejected } /// /// The result of an /// call. Carries either an authenticated identity or a rejection /// reason. /// /// /// /// The authenticator's job is to validate the token and produce a /// raw (optionally implementing /// ). Role mapping per OPC 10000-18 /// §4.4.1 is performed separately by IRoleManager on the /// returned identity — authenticators MUST NOT pre-grant role /// NodeIds. /// /// /// This separation preserves the existing layering: token validation /// (this interface) → claim normalisation /// ( on the identity) → /// Part 18 role mapping (IRoleManager). /// /// public readonly record struct AuthenticationResult { private AuthenticationResult( AuthenticationOutcome outcome, IUserIdentity? identity, ServiceResult? error) { Outcome = outcome; Identity = identity; Error = error; } /// /// The outcome of the authentication attempt. /// public AuthenticationOutcome Outcome { get; } /// /// The authenticated identity when /// is ; /// otherwise . /// public IUserIdentity? Identity { get; } /// /// The rejection reason when /// is ; /// otherwise . /// public ServiceResult? Error { get; } /// /// Indicates the authenticator does not handle this token. /// public static AuthenticationResult NotHandled { get; } = new(AuthenticationOutcome.NotHandled, null, null); /// /// Indicates the token was accepted and produced /// . /// public static AuthenticationResult Accept(IUserIdentity identity) { if (identity == null) { throw new ArgumentNullException(nameof(identity)); } return new AuthenticationResult( AuthenticationOutcome.Accepted, identity, null); } /// /// Indicates the token was rejected. The reason is reported back /// to the client as the ActivateSession response error. /// public static AuthenticationResult Reject(ServiceResult error) { if (error == null) { throw new ArgumentNullException(nameof(error)); } return new AuthenticationResult( AuthenticationOutcome.Rejected, null, error); } } /// /// Context passed to an while /// the server is validating an incoming ActivateSession user /// identity token. /// /// /// The decoded, decrypted token (per Part 4 §5.6.4): for /// UserName the password is already in the clear, for /// IssuedToken the issued payload is already decrypted, for /// X509 the wire certificate is parsed but not validated. /// /// /// The endpoint policy the client selected. Carries the OPC UA /// security policy used to encrypt the token and, for JWT, /// / /// . /// /// /// The endpoint that received the request. Authenticators MAY refuse /// to issue an identity for an unsecured endpoint /// () for token types that /// require channel protection. /// /// /// Encoder factories + telemetry. /// /// /// The ApplicationInstance certificate bound to the secure channel, when supplied by the client. /// /// /// The ApplicationUri from the session diagnostics for the connecting application, when known. /// public readonly record struct AuthenticationContext( IUserIdentityTokenHandler TokenHandler, UserTokenPolicy UserTokenPolicy, EndpointDescription EndpointDescription, IServiceMessageContext MessageContext, Certificate? ChannelCertificate = null, string? ChannelApplicationUri = null); /// /// Validates a single OPC UA user identity token type / profile. /// Plugged into an which /// dispatches by and (for issued tokens) /// by the IssuedTokenType profile URI. /// /// /// /// Implementations are responsible for token validation only: /// /// /// Anonymous → trivially accept. /// UserName → verify the decrypted password against an /// IUserDatabase; honour lockout / MustChangePassword. /// X509 → verify the user certificate against an /// ICertificateValidator bound to the Users /// trust list and extract subject / SAN claims. /// Issued (JWT) → verify the JWT signature against an /// IIssuerKeyResolver, check iss / aud /// / exp, and populate /// . /// /// /// Authenticators MUST NOT perform Part 18 role mapping — that is /// the sole responsibility of IRoleManager.ResolveGrantedRoles /// invoked by the SessionManager after the authenticator /// returns. /// /// public interface IUserTokenAuthenticator { /// /// The OPC UA user-token type this authenticator handles. /// UserTokenType TokenType { get; } /// /// For authenticators, /// the IssuedTokenType profile URI handled (e.g. /// ). /// for non-issued-token authenticators. /// string? IssuedTokenProfileUri { get; } /// /// Validate the token. Returns one of: /// , /// , or /// (when the /// authenticator declines based on policy / endpoint, e.g. /// "this JWT issuer only accepts signed channels"). /// ValueTask AuthenticateAsync( AuthenticationContext context, CancellationToken ct = default); } }