pub struct CasAuthPlugin {
idp_uri: String,
service: Option<String>,
ticket_param: String,
ssl_verify: bool,
timeout: Duration,
sealer: Option<CookieSealer>,
cookie_name: String,
cookie_path: String,
cookie_lifetime: u64,
logout_path: Option<String>,
backend: SessionBackend,
client: Arc<OutboundClient>,
}Expand description
Validates CAS service tickets and, in interactive mode, runs the SSO flow.
Fields§
§idp_uri: StringCAS server base URI (e.g. https://cas.example.org/cas).
service: Option<String>Service URL sent to /serviceValidate; when unset it is derived from the
request (scheme://host/path). Must match the service the ticket was
issued for, so an explicit value is strongly recommended.
ticket_param: StringQuery parameter the ticket is read from (default ticket).
ssl_verify: boolWhether the CAS server’s TLS certificate is verified.
timeout: DurationWhole-call deadline for the validation callout.
sealer: Option<CookieSealer>When set, interactive SSO login is enabled and this seals/opens the
session cookie. None keeps the stateless ticket-validator behavior.
Name of the session cookie (interactive mode).
Path attribute of the session cookie (interactive mode). Scope it to a
subpath (e.g. /app_a) so nodes on distinct subpaths keep independent
sessions. Defaults to /.
Session cookie lifetime in seconds (interactive mode).
logout_path: Option<String>Optional logout path; a request to it clears the session cookie.
backend: SessionBackendWhere the session payload lives: sealed in the cookie itself, or a
server-side store keyed by a bare id in the cookie. See
session.storage / session.store in CasAuthPlugin::from_config.
client: Arc<OutboundClient>Implementations§
Source§impl CasAuthPlugin
impl CasAuthPlugin
Sourcepub fn from_config(
config: &HashMap<String, Value>,
resources: &Arc<PluginResources>,
) -> Result<Self, String>
pub fn from_config( config: &HashMap<String, Value>, resources: &Arc<PluginResources>, ) -> Result<Self, String>
Builds the plugin from node config.
Accepted keys:
idp_uri(string, required): CAS server base URI. The validation request goes to<idp_uri>/serviceValidate.service(string, optional): service URL passed to/serviceValidate. When omitted it is derived from the request scheme/host/path; because CAS requires the validated service to match the login service, set this explicitly whenever the gateway sits behind a proxy.ticket_param(string, default"ticket"): query parameter carrying the CAS service ticket.ssl_verify(bool, defaulttrue): verify the CAS server TLS cert.timeout_ms(u64, default3000): callout deadline.
Interactive-mode keys (present ⇒ interactive login is enabled):
session_secret(string) orsession.secret(string): signing/encryption secret for the session cookie. Setting it turns on the SSO flow.session.cookie.name(string, default"cas_session"): session cookie name.session.cookie.path(string, default"/"): session cookiePath; scope to a subpath (e.g./app_a) for independent per-app sessions.session.cookie.lifetime(u64 seconds, default3600): cookie lifetime.logout_path(string, optional): request path that clears the session cookie and redirects to/.
type: cas-auth
config:
idp_uri: https://cas.example.org/cas
service: https://app.example.org/
ssl_verify: true
session:
secret: ${CAS_SESSION_SECRET}
cookie: { name: cas_session, lifetime: 3600 }Sourcefn reject(
&self,
ctx: Context,
message: &str,
) -> Result<PluginOutput, PluginExecutionError>
fn reject( &self, ctx: Context, message: &str, ) -> Result<PluginOutput, PluginExecutionError>
Builds a 401 rejection and exits on the denied port.
Sourcefn infra_error(&self, ctx: Context, message: String) -> PluginExecutionError
fn infra_error(&self, ctx: Context, message: String) -> PluginExecutionError
Builds a genuine infrastructure-failure Err (the CAS server was
unreachable, timed out, or answered /serviceValidate with a non-200).
Unlike CasAuthPlugin::reject, this exits through the error port
because the node could not do its job, not because a presented ticket
was deliberately refused — and the prepared response is the shared
502 provider_error shape, not a 401 that would read as a bad ticket.
Sourcefn store_error(ctx: Context, e: StoreError) -> PluginExecutionError
fn store_error(ctx: Context, e: StoreError) -> PluginExecutionError
Session-store outage: 503 through the error port. Deliberately NOT 401 — a store outage is not “unauthenticated”.
Sourcefn redirect(
&self,
ctx: Context,
location: String,
set_cookies: Vec<String>,
) -> Result<PluginOutput, PluginExecutionError>
fn redirect( &self, ctx: Context, location: String, set_cookies: Vec<String>, ) -> Result<PluginOutput, PluginExecutionError>
Builds a 302 early-exit carrying the prepared response, and exits on
the redirect port. Wire the node’s redirect edge to client.in so
this reaches the browser.
Sourcefn service_url(&self, ctx: &Context) -> String
fn service_url(&self, ctx: &Context) -> String
The service URL sent to /serviceValidate: the configured value, or one
derived from the request (scheme://host/path, without the query so the
ticket is dropped).
Sourcefn session_attrs(&self, ctx: &Context) -> CookieAttrs<'_>
fn session_attrs(&self, ctx: &Context) -> CookieAttrs<'_>
Cookie attributes for the session cookie: HttpOnly, SameSite=Lax, and
Secure only over HTTPS (so plain-HTTP dev works).
Sourcefn attach_user(&self, ctx: &mut Context, user: &str)
fn attach_user(&self, ctx: &mut Context, user: &str)
Attaches the authenticated user to the request/context.
Sourceasync fn read_session(
&self,
ctx: &Context,
) -> Result<Option<String>, StoreError>
async fn read_session( &self, ctx: &Context, ) -> Result<Option<String>, StoreError>
Reads the session cookie via the configured backend, returning the
authenticated user. Ok(None) = unauthenticated (no cookie/sealer, or
an unopenable/unparseable payload); Err = store outage (503 via
CasAuthPlugin::store_error), never a silent re-login.
Sourceasync fn cas_validate(
&self,
ctx: &Context,
ticket: &str,
) -> Result<String, CasError>
async fn cas_validate( &self, ctx: &Context, ticket: &str, ) -> Result<String, CasError>
Validates a CAS ticket against /serviceValidate, returning the user.
A transport failure or a non-200 reply is a CasError::Infra (the
node could not reach a verdict); a well-formed authentication-failure
reply is a CasError::Denied (CAS gave its verdict: no).
Sourceasync fn execute_interactive(
&self,
ctx: Context,
) -> Result<PluginOutput, PluginExecutionError>
async fn execute_interactive( &self, ctx: Context, ) -> Result<PluginOutput, PluginExecutionError>
Interactive SSO flow: session cookie → callback → begin login.
Sourceasync fn execute_stateless(
&self,
ctx: Context,
) -> Result<PluginOutput, PluginExecutionError>
async fn execute_stateless( &self, ctx: Context, ) -> Result<PluginOutput, PluginExecutionError>
Stateless ticket validation (the default, pre-interactive behavior).
Trait Implementations§
Source§impl Plugin for CasAuthPlugin
impl Plugin for CasAuthPlugin
Source§fn plugin_type(&self) -> &str
fn plugin_type(&self) -> &str
Source§fn execute<'life0, 'async_trait>(
&'life0 self,
ctx: Context,
) -> Pin<Box<dyn Future<Output = Result<PluginOutput, PluginExecutionError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn execute<'life0, 'async_trait>(
&'life0 self,
ctx: Context,
) -> Pin<Box<dyn Future<Output = Result<PluginOutput, PluginExecutionError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn reads_response_body(&self) -> bool
fn reads_response_body(&self) -> bool
context.response.body. Read moreSource§fn cache_target(&self) -> Option<CacheTarget>
fn cache_target(&self) -> Option<CacheTarget>
proxy-cache half. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for CasAuthPlugin
impl !UnwindSafe for CasAuthPlugin
impl Freeze for CasAuthPlugin
impl Send for CasAuthPlugin
impl Sync for CasAuthPlugin
impl Unpin for CasAuthPlugin
impl UnsafeUnpin for CasAuthPlugin
Blanket Implementations§
§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more