You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Working legacy login endpoint
This commit is contained in:
@ -12,9 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use axum::{response::IntoResponse, Json};
|
||||
use axum::{response::IntoResponse, Extension, Json};
|
||||
use hyper::StatusCode;
|
||||
use mas_config::MatrixConfig;
|
||||
use mas_data_model::TokenType;
|
||||
use mas_storage::compat::compat_login;
|
||||
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct MatrixError {
|
||||
@ -73,11 +78,84 @@ pub enum LoginIdentifier {
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
pub(crate) async fn post(Json(input): Json<IncomingLogin>) -> impl IntoResponse {
|
||||
tracing::info!(?input, "Got Matrix login");
|
||||
MatrixError {
|
||||
errcode: "M_UNKNOWN",
|
||||
error: "Not implemented",
|
||||
status: StatusCode::NOT_IMPLEMENTED,
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SuccessfulLogin {
|
||||
access_token: String,
|
||||
device_id: String,
|
||||
user_id: String,
|
||||
}
|
||||
|
||||
pub enum RouteError {
|
||||
Internal(Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
Unsupported,
|
||||
LoginFailed,
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for RouteError {
|
||||
fn from(e: sqlx::Error) -> Self {
|
||||
Self::Internal(Box::new(e))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResponse for RouteError {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
match self {
|
||||
Self::Internal(_e) => MatrixError {
|
||||
errcode: "M_UNKNOWN",
|
||||
error: "Internal server error",
|
||||
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||
},
|
||||
Self::Unsupported => MatrixError {
|
||||
errcode: "M_UNRECOGNIZED",
|
||||
error: "Invalid login type",
|
||||
status: StatusCode::BAD_REQUEST,
|
||||
},
|
||||
Self::LoginFailed => MatrixError {
|
||||
errcode: "M_UNAUTHORIZED",
|
||||
error: "Invalid username/password",
|
||||
status: StatusCode::FORBIDDEN,
|
||||
},
|
||||
}
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn post(
|
||||
Extension(pool): Extension<PgPool>,
|
||||
Extension(config): Extension<MatrixConfig>,
|
||||
Json(input): Json<IncomingLogin>,
|
||||
) -> Result<impl IntoResponse, RouteError> {
|
||||
let mut conn = pool.acquire().await?;
|
||||
let (username, password) = match input {
|
||||
IncomingLogin::Password {
|
||||
identifier: LoginIdentifier::User { user },
|
||||
password,
|
||||
} => (user, password),
|
||||
_ => {
|
||||
return Err(RouteError::Unsupported);
|
||||
}
|
||||
};
|
||||
|
||||
let (token, device_id) = {
|
||||
let mut rng = thread_rng();
|
||||
let token = TokenType::CompatAccessToken.generate(&mut rng);
|
||||
let device_id: String = rng
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(10)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
(token, device_id)
|
||||
};
|
||||
|
||||
let (token, user) = compat_login(&mut conn, &username, &password, device_id, token)
|
||||
.await
|
||||
.map_err(|_| RouteError::LoginFailed)?;
|
||||
|
||||
let user_id = format!("@{}:{}", user.username, config.homeserver);
|
||||
|
||||
Ok(Json(SuccessfulLogin {
|
||||
access_token: token.token,
|
||||
device_id: token.device_id,
|
||||
user_id,
|
||||
}))
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ use axum::{
|
||||
Router,
|
||||
};
|
||||
use hyper::header::{ACCEPT, ACCEPT_LANGUAGE, AUTHORIZATION, CONTENT_LANGUAGE, CONTENT_TYPE};
|
||||
use mas_config::Encrypter;
|
||||
use mas_config::{Encrypter, MatrixConfig};
|
||||
use mas_email::Mailer;
|
||||
use mas_http::CorsLayerExt;
|
||||
use mas_jose::StaticKeystore;
|
||||
@ -53,6 +53,7 @@ pub fn router<B>(
|
||||
encrypter: &Encrypter,
|
||||
mailer: &Mailer,
|
||||
url_builder: &UrlBuilder,
|
||||
matrix_config: &MatrixConfig,
|
||||
) -> Router<B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
@ -186,4 +187,5 @@ where
|
||||
.layer(Extension(encrypter.clone()))
|
||||
.layer(Extension(url_builder.clone()))
|
||||
.layer(Extension(mailer.clone()))
|
||||
.layer(Extension(matrix_config.clone()))
|
||||
}
|
||||
|
@ -18,21 +18,40 @@ use mas_axum_utils::client_authorization::{ClientAuthorization, CredentialsVerif
|
||||
use mas_config::Encrypter;
|
||||
use mas_data_model::{TokenFormatError, TokenType};
|
||||
use mas_iana::oauth::{OAuthClientAuthenticationMethod, OAuthTokenTypeHint};
|
||||
use mas_storage::oauth2::{
|
||||
access_token::{lookup_active_access_token, AccessTokenLookupError},
|
||||
client::ClientFetchError,
|
||||
refresh_token::{lookup_active_refresh_token, RefreshTokenLookupError},
|
||||
use mas_storage::{
|
||||
compat::{lookup_active_compat_access_token, CompatAccessTokenLookupError},
|
||||
oauth2::{
|
||||
access_token::{lookup_active_access_token, AccessTokenLookupError},
|
||||
client::ClientFetchError,
|
||||
refresh_token::{lookup_active_refresh_token, RefreshTokenLookupError},
|
||||
},
|
||||
};
|
||||
use oauth2_types::{
|
||||
requests::{IntrospectionRequest, IntrospectionResponse},
|
||||
scope::ScopeToken,
|
||||
};
|
||||
use oauth2_types::requests::{IntrospectionRequest, IntrospectionResponse};
|
||||
use sqlx::PgPool;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RouteError {
|
||||
#[error(transparent)]
|
||||
Internal(Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
|
||||
#[error("could not find client")]
|
||||
ClientNotFound,
|
||||
|
||||
#[error("client is not allowed to introspect")]
|
||||
NotAllowed,
|
||||
|
||||
#[error("unknown token")]
|
||||
UnknownToken,
|
||||
|
||||
#[error("bad request")]
|
||||
BadRequest,
|
||||
ClientCredentialsVerification(CredentialsVerificationError),
|
||||
|
||||
#[error(transparent)]
|
||||
ClientCredentialsVerification(#[from] CredentialsVerificationError),
|
||||
}
|
||||
|
||||
impl IntoResponse for RouteError {
|
||||
@ -88,8 +107,8 @@ impl From<AccessTokenLookupError> for RouteError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RefreshTokenLookupError> for RouteError {
|
||||
fn from(e: RefreshTokenLookupError) -> Self {
|
||||
impl From<CompatAccessTokenLookupError> for RouteError {
|
||||
fn from(e: CompatAccessTokenLookupError) -> Self {
|
||||
if e.not_found() {
|
||||
Self::UnknownToken
|
||||
} else {
|
||||
@ -98,9 +117,13 @@ impl From<RefreshTokenLookupError> for RouteError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CredentialsVerificationError> for RouteError {
|
||||
fn from(e: CredentialsVerificationError) -> Self {
|
||||
Self::ClientCredentialsVerification(e)
|
||||
impl From<RefreshTokenLookupError> for RouteError {
|
||||
fn from(e: RefreshTokenLookupError) -> Self {
|
||||
if e.not_found() {
|
||||
Self::UnknownToken
|
||||
} else {
|
||||
Self::Internal(Box::new(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,6 +142,7 @@ const INACTIVE: IntrospectionResponse = IntrospectionResponse {
|
||||
jti: None,
|
||||
};
|
||||
|
||||
#[tracing::instrument(skip_all, err)]
|
||||
pub(crate) async fn post(
|
||||
Extension(pool): Extension<PgPool>,
|
||||
Extension(encrypter): Extension<Encrypter>,
|
||||
@ -192,6 +216,29 @@ pub(crate) async fn post(
|
||||
jti: None,
|
||||
}
|
||||
}
|
||||
TokenType::CompatAccessToken => {
|
||||
let (token, user) = lookup_active_compat_access_token(&mut conn, token).await?;
|
||||
|
||||
let device_scope: ScopeToken = format!("urn:matrix:device:{}", token.device_id)
|
||||
.parse()
|
||||
.unwrap();
|
||||
let scope = [device_scope].into_iter().collect();
|
||||
|
||||
IntrospectionResponse {
|
||||
active: true,
|
||||
scope: Some(scope),
|
||||
client_id: Some("legacy".into()),
|
||||
username: Some(user.username),
|
||||
token_type: Some(OAuthTokenTypeHint::AccessToken),
|
||||
exp: None,
|
||||
iat: Some(token.created_at),
|
||||
nbf: Some(token.created_at),
|
||||
sub: Some(user.sub),
|
||||
aud: None,
|
||||
iss: None,
|
||||
jti: None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Json(reply))
|
||||
|
Reference in New Issue
Block a user