v.34.1
This commit is contained in:
1 parent
4afa88a65e
commit
2ab44c4c62
49 files changed
+1523
-176
No files matched your search
+39
-6
@@ -120,8 +120,7 @@ async fn guard(State(state): State<Arc<App>>, mut request: Request, next: Next)
|
||||
// Pinned browser origin is panel-only. Certificate automation using API
|
||||
// credentials keeps the original forwarding/TLS authorization semantics.
|
||||
let automation_credentials = headers.contains_key(CERTIFICATE_API_KEY_HEADER)
|
||||
|| (headers.contains_key(AUTHORIZATION)
|
||||
&& certificate_api_operation(request.method(), request.uri().path()).is_some());
|
||||
|| headers.contains_key(AUTHORIZATION);
|
||||
let pinned_authority_result = if automation_credentials {
|
||||
Ok(None)
|
||||
} else {
|
||||
@@ -173,7 +172,10 @@ async fn guard(State(state): State<Arc<App>>, mut request: Request, next: Next)
|
||||
let secret = auth::cookie_secret(headers);
|
||||
let certificate_api_operation = certificate_api_operation(request.method(), &path);
|
||||
let mut certificate_api_access = None;
|
||||
let certificate_api_session = if let Some(operation) = certificate_api_operation.as_ref() {
|
||||
let certificate_api_session = if headers.contains_key(CERTIFICATE_API_KEY_HEADER) {
|
||||
let Some(operation) = certificate_api_operation.as_ref() else {
|
||||
return secure(reject(StatusCode::FORBIDDEN, "certificate_api.invalid_route"));
|
||||
};
|
||||
match certificate_api_credentials(headers) {
|
||||
Ok(None) => None,
|
||||
Ok(Some((key_id, token))) => {
|
||||
@@ -241,7 +243,36 @@ async fn guard(State(state): State<Arc<App>>, mut request: Request, next: Next)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let external_certificate_api = certificate_api_session.is_some();
|
||||
let general_api_session = if certificate_api_session.is_none() && headers.contains_key(AUTHORIZATION) {
|
||||
// No cookies are accepted as a fallback when a malformed Bearer header is supplied.
|
||||
let bearer = single_header(headers, AUTHORIZATION.as_str())
|
||||
.and_then(|header| header.strip_prefix("Bearer "));
|
||||
let Some(token) = bearer.filter(|value| valid_certificate_api_token(value)) else {
|
||||
return secure(reject(StatusCode::UNAUTHORIZED, "api_token.invalid_token"));
|
||||
};
|
||||
let Some(peer) = peer else {
|
||||
return secure(reject(StatusCode::FORBIDDEN, "api_token.peer_required"));
|
||||
};
|
||||
if !peer.0.ip().is_loopback() && scheme != "https" {
|
||||
return secure(reject(StatusCode::FORBIDDEN, "api_token.https_required"));
|
||||
}
|
||||
let hash = auth::secret_hash(token);
|
||||
let peer_ip = crate::vhost::canonical_ip(peer.0.ip());
|
||||
let grant = match state.store.verify_api_token(&hash, peer_ip).await {
|
||||
Ok(Some(grant)) => grant,
|
||||
Ok(None) => return secure(reject(StatusCode::UNAUTHORIZED, "api_token.invalid_token_or_ip")),
|
||||
Err(error) => return secure(auth::internal(error).into_response()),
|
||||
};
|
||||
if !general_api_token_allowed(request.method(), &path, &grant.permission) {
|
||||
return secure(reject(StatusCode::FORBIDDEN, "api_token.insufficient_permission"));
|
||||
}
|
||||
Some(Session {
|
||||
token_hash: hash, csrf: String::new(),
|
||||
username: format!("api-token:{}", grant.id),
|
||||
expires_at: auth::now().saturating_add(60), generation: 0,
|
||||
})
|
||||
} else { None };
|
||||
let external_credential = certificate_api_session.is_some() || general_api_session.is_some();
|
||||
let session_seconds = state
|
||||
.config
|
||||
.load()
|
||||
@@ -254,6 +285,8 @@ async fn guard(State(state): State<Arc<App>>, mut request: Request, next: Next)
|
||||
// login resources and capability discovery never load operational state.
|
||||
let session = if certificate_api_session.is_some() {
|
||||
certificate_api_session
|
||||
} else if general_api_session.is_some() {
|
||||
general_api_session
|
||||
} else if !public || panel_document_path(&path) {
|
||||
match secret.as_deref() {
|
||||
Some(secret) => match state
|
||||
@@ -272,7 +305,7 @@ async fn guard(State(state): State<Arc<App>>, mut request: Request, next: Next)
|
||||
if !public && session.is_none() {
|
||||
return secure(unauthorized(&request));
|
||||
}
|
||||
if unsafe_method && !external_certificate_api {
|
||||
if unsafe_method && !external_credential {
|
||||
if single_header(headers, "origin")
|
||||
.is_none_or(|origin| !admin_origin_matches(origin, scheme, &external_authority))
|
||||
|| single_header(headers, "x-rustproxy-request") != Some("1")
|
||||
@@ -304,7 +337,7 @@ async fn guard(State(state): State<Arc<App>>, mut request: Request, next: Next)
|
||||
path.as_str(),
|
||||
"/api/auth/logout" | "/api/auth/logout-all" | "/api/auth/password"
|
||||
);
|
||||
if refresh_session_cookie {
|
||||
if refresh_session_cookie && !external_credential {
|
||||
if let (Some(secret), Some(session)) = (secret.as_deref(), session.as_ref()) {
|
||||
let remaining = session.expires_at.saturating_sub(auth::now());
|
||||
if remaining > 0 {
|
||||
|
||||
Reference in new issue
Block a user