Add authorization handler.

This commit is contained in:
Anatoly Sablin
2019-10-01 23:52:01 +03:00
parent 5521c0c338
commit bc8795e940
10 changed files with 154 additions and 59 deletions

View File

@@ -0,0 +1,69 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.http.undertow.handler;
import io.kamax.mxisd.auth.AccountManager;
import io.kamax.mxisd.exception.InvalidCredentialsException;
import io.kamax.mxisd.storage.ormlite.dao.AccountDao;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AuthorizationHandler extends BasicHttpHandler {
private static final Logger log = LoggerFactory.getLogger(AuthorizationHandler.class);
private final AccountManager accountManager;
private final HttpHandler child;
public static AuthorizationHandler around(AccountManager accountManager, HttpHandler child) {
return new AuthorizationHandler(accountManager, child);
}
private AuthorizationHandler(AccountManager accountManager, HttpHandler child) {
this.accountManager = accountManager;
this.child = child;
}
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
String token = findAccessToken(exchange).orElse(null);
if (token == null) {
log.error("Unauthorized request from: {}", exchange.getHostAndPort());
throw new InvalidCredentialsException();
}
AccountDao account = accountManager.findAccount(token);
if (account == null) {
log.error("Account not found from request from: {}", exchange.getHostAndPort());
throw new InvalidCredentialsException();
}
if (account.getExpiresIn() < System.currentTimeMillis()) {
log.error("Account for '{}' from: {}", account.getUserId(), exchange.getHostAndPort());
accountManager.deleteAccount(token);
throw new InvalidCredentialsException();
}
log.trace("Access for '{}' allowed", account.getUserId());
child.handleRequest(exchange);
}
}

View File

@@ -28,6 +28,7 @@ import io.kamax.mxisd.exception.AccessTokenNotFoundException;
import io.kamax.mxisd.exception.HttpMatrixException;
import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.proxy.Response;
import io.kamax.mxisd.util.OptionalUtil;
import io.kamax.mxisd.util.RestClientUtils;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
@@ -55,6 +56,24 @@ public abstract class BasicHttpHandler implements HttpHandler {
private static final Logger log = LoggerFactory.getLogger(BasicHttpHandler.class);
protected final static String headerName = "Authorization";
protected final static String headerValuePrefix = "Bearer ";
private final static String parameterName = "access_token";
Optional<String> findAccessTokenInHeaders(HttpServerExchange exchange) {
return Optional.ofNullable(exchange.getRequestHeaders().getFirst(headerName))
.filter(header -> StringUtils.startsWith(header, headerValuePrefix))
.map(header -> header.substring(headerValuePrefix.length()));
}
Optional<String> findAccessTokenInQuery(HttpServerExchange exchange) {
return Optional.ofNullable(exchange.getQueryParameters().getOrDefault(parameterName, new LinkedList<>()).peekFirst());
}
public Optional<String> findAccessToken(HttpServerExchange exchange) {
return OptionalUtil.findFirst(() -> findAccessTokenInHeaders(exchange), () -> findAccessTokenInQuery(exchange));
}
protected String getAccessToken(HttpServerExchange exchange) {
return Optional.ofNullable(exchange.getRequestHeaders().getFirst("Authorization"))
.flatMap(v -> {

View File

@@ -21,35 +21,11 @@
package io.kamax.mxisd.http.undertow.handler;
import io.kamax.mxisd.exception.AccessTokenNotFoundException;
import io.kamax.mxisd.util.OptionalUtil;
import io.undertow.server.HttpServerExchange;
import org.apache.commons.lang3.StringUtils;
import java.util.LinkedList;
import java.util.Optional;
public abstract class HomeserverProxyHandler extends BasicHttpHandler {
protected final static String headerName = "Authorization";
protected final static String headerValuePrefix = "Bearer ";
private final static String parameterName = "access_token";
Optional<String> findAccessTokenInHeaders(HttpServerExchange exchange) {
return Optional.ofNullable(exchange.getRequestHeaders().getFirst(headerName))
.filter(header -> StringUtils.startsWith(header, headerValuePrefix))
.map(header -> header.substring(headerValuePrefix.length()));
}
Optional<String> findAccessTokenInQuery(HttpServerExchange exchange) {
return Optional.ofNullable(exchange.getQueryParameters().getOrDefault(parameterName, new LinkedList<>()).peekFirst());
}
public Optional<String> findAccessToken(HttpServerExchange exchange) {
return OptionalUtil.findFirst(() -> findAccessTokenInHeaders(exchange), () -> findAccessTokenInQuery(exchange));
}
public String getAccessToken(HttpServerExchange exchange) {
return findAccessToken(exchange).orElseThrow(AccessTokenNotFoundException::new);
}
}

View File

@@ -22,6 +22,7 @@ package io.kamax.mxisd.http.undertow.handler.auth.v2;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.auth.AccountManager;
import io.kamax.mxisd.exception.InvalidCredentialsException;
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger;
@@ -31,7 +32,7 @@ public class AccountGetUserInfoHandler extends BasicHttpHandler {
public static final String Path = "/_matrix/identity/v2/account";
private static final Logger log = LoggerFactory.getLogger(AccountGetUserInfoHandler.class);
private static final Logger LOGGER = LoggerFactory.getLogger(AccountGetUserInfoHandler.class);
private final AccountManager accountManager;
@@ -41,13 +42,11 @@ public class AccountGetUserInfoHandler extends BasicHttpHandler {
@Override
public void handleRequest(HttpServerExchange exchange) {
String token = getQueryParameter(exchange, "access_token");
if (token == null) {
token = getAccessToken(exchange);
}
LOGGER.info("Get User Info.");
String token = findAccessToken(exchange).orElseThrow(InvalidCredentialsException::new);
String userId = accountManager.getUserId(token);
LOGGER.info("Account found: {}", userId);
respond(exchange, GsonUtil.makeObj("user_id", userId));
}
}

View File

@@ -21,6 +21,7 @@
package io.kamax.mxisd.http.undertow.handler.auth.v2;
import io.kamax.mxisd.auth.AccountManager;
import io.kamax.mxisd.exception.InvalidCredentialsException;
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger;
@@ -28,9 +29,9 @@ import org.slf4j.LoggerFactory;
public class AccountLogoutHandler extends BasicHttpHandler {
public static final String Path = "/_matrix/identity/v2/account";
public static final String Path = "/_matrix/identity/v2/account/logout";
private static final Logger log = LoggerFactory.getLogger(AccountLogoutHandler.class);
private static final Logger LOGGER = LoggerFactory.getLogger(AccountLogoutHandler.class);
private final AccountManager accountManager;
@@ -40,10 +41,8 @@ public class AccountLogoutHandler extends BasicHttpHandler {
@Override
public void handleRequest(HttpServerExchange exchange) {
String token = getQueryParameter(exchange, "access_token");
if (token == null) {
token = getAccessToken(exchange);
}
LOGGER.info("Logout.");
String token = findAccessToken(exchange).orElseThrow(InvalidCredentialsException::new);
accountManager.logout(token);

View File

@@ -28,11 +28,13 @@ import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
public class AccountRegisterHandler extends BasicHttpHandler {
public static final String Path = "/_matrix/identity/v2/account/register";
private static final Logger log = LoggerFactory.getLogger(AccountRegisterHandler.class);
private static final Logger LOGGER = LoggerFactory.getLogger(AccountRegisterHandler.class);
private final AccountManager accountManager;
@@ -43,6 +45,12 @@ public class AccountRegisterHandler extends BasicHttpHandler {
@Override
public void handleRequest(HttpServerExchange exchange) {
OpenIdToken openIdToken = parseJsonTo(exchange, OpenIdToken.class);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Registration from domain: {}, expired at {}", openIdToken.getMatrixServerName(),
new Date(openIdToken.getExpiredIn()));
}
String token = accountManager.register(openIdToken);
respond(exchange, GsonUtil.makeObj("token", token));
}