package io.undertow.security.impl;
import static io.undertow.UndertowMessages.MESSAGES;
import io.undertow.UndertowLogger;
import io.undertow.security.api.NotificationReceiver;
import io.undertow.security.api.SecurityContext;
import io.undertow.security.api.SecurityNotification;
import io.undertow.security.api.SecurityNotification.EventType;
import io.undertow.security.idm.Account;
import io.undertow.server.HttpServerExchange;
public abstract class AbstractSecurityContext implements SecurityContext {
private boolean authenticationRequired;
protected final HttpServerExchange exchange;
private Node<NotificationReceiver> notificationReceivers = null;
private Account account;
private String mechanismName;
protected AbstractSecurityContext(final HttpServerExchange exchange) {
this.exchange = exchange;
}
@Override
public void setAuthenticationRequired() {
authenticationRequired = true;
}
@Override
public boolean isAuthenticationRequired() {
return authenticationRequired;
}
@Override
public boolean isAuthenticated() {
return account != null;
}
@Override
public Account getAuthenticatedAccount() {
return account;
}
@Override
public String getMechanismName() {
return mechanismName;
}
@Override
public void authenticationComplete(Account account, String mechanism, final boolean cachingRequired) {
authenticationComplete(account, mechanism, false, cachingRequired);
}
protected void authenticationComplete(Account account, String mechanism, boolean programatic, final boolean cachingRequired) {
this.account = account;
this.mechanismName = mechanism;
UndertowLogger.SECURITY_LOGGER.debugf("Authenticated as %s, roles %s", account.getPrincipal().getName(), account.getRoles());
sendNoticiation(new SecurityNotification(exchange, EventType.AUTHENTICATED, account, mechanism, programatic,
MESSAGES.userAuthenticated(account.getPrincipal().getName()), cachingRequired));
}
@Override
public void authenticationFailed(String message, String mechanism) {
UndertowLogger.SECURITY_LOGGER.debugf("Authentication failed with message %s and mechanism %s for %s", message, mechanism, exchange);
sendNoticiation(new SecurityNotification(exchange, EventType.FAILED_AUTHENTICATION, null, mechanism, false, message, true));
}
@Override
public void registerNotificationReceiver(NotificationReceiver receiver) {
if(notificationReceivers == null) {
notificationReceivers = new Node<>(receiver);
} else {
Node<NotificationReceiver> cur = notificationReceivers;
while (cur.next != null) {
cur = cur.next;
}
cur.next = new Node<>(receiver);
}
}
@Override
public void removeNotificationReceiver(NotificationReceiver receiver) {
Node<NotificationReceiver> cur = notificationReceivers;
if(receiver.equals(cur.item)) {
notificationReceivers = cur.next;
} else {
Node<NotificationReceiver> old = cur;
while (cur.next != null) {
cur = cur.next;
if(receiver.equals(cur.item)) {
old.next = cur.next;
}
old = cur;
}
}
}
private void sendNoticiation(final SecurityNotification notification) {
Node<NotificationReceiver> cur = notificationReceivers;
while (cur != null) {
cur.item.handleNotification(notification);
cur = cur.next;
}
}
@Override
public void logout() {
if (!isAuthenticated()) {
return;
}
UndertowLogger.SECURITY_LOGGER.debugf("Logged out %s", exchange);
sendNoticiation(new SecurityNotification(exchange, SecurityNotification.EventType.LOGGED_OUT, account, mechanismName, true,
MESSAGES.userLoggedOut(account.getPrincipal().getName()), true));
this.account = null;
this.mechanismName = null;
}
protected static final class Node<T> {
final T item;
Node<T> next;
private Node(T item) {
this.item = item;
}
}
}