Rename audit to events

This commit is contained in:
Stian Thorgersen committed 2014-08-28 10:56:37 +02:00
1 parent b50ab14a0a
commit 3bfe3d256e
143 files changed
+1132 -1142

No files matched your search

+1 -1
View File
@@ -39,7 +39,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-audit-api</artifactId>
<artifactId>keycloak-events-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
@@ -1,57 +0,0 @@
package org.keycloak.services.managers;
import org.jboss.logging.Logger;
import org.keycloak.ClientConnection;
import org.keycloak.audit.Audit;
import org.keycloak.audit.AuditListener;
import org.keycloak.audit.AuditProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class AuditManager {
private Logger log = Logger.getLogger(AuditManager.class);
private RealmModel realm;
private KeycloakSession session;
private ClientConnection clientConnection;
public AuditManager(RealmModel realm, KeycloakSession session, ClientConnection clientConnection) {
this.realm = realm;
this.session = session;
this.clientConnection = clientConnection;
}
public Audit createAudit() {
List<AuditListener> listeners = new LinkedList<AuditListener>();
if (realm.isAuditEnabled()) {
AuditProvider auditProvider = session.getProvider(AuditProvider.class);
if (auditProvider != null) {
listeners.add(auditProvider);
} else {
log.error("Audit enabled, but no audit provider configured");
}
}
if (realm.getAuditListeners() != null) {
for (String id : realm.getAuditListeners()) {
AuditListener listener = session.getProvider(AuditListener.class, id);
if (listener != null) {
listeners.add(listener);
} else {
log.error("Audit listener '" + id + "' registered, but not found");
}
}
}
return new Audit(listeners, realm, clientConnection.getRemoteAddr());
}
}
@@ -185,7 +185,7 @@ public class BruteForceProtector implements Runnable {
session.close();
}
} catch (Exception e) {
logger.error("Failed processing event", e);
logger.error("Failed processing type", e);
}
} catch (InterruptedException e) {
break;
@@ -228,7 +228,7 @@ public class BruteForceProtector implements Runnable {
try {
FailedLogin event = new FailedLogin(realm.getId(), username, clientConnection.getRemoteAddr());
queue.offer(event);
// wait a minimum of seconds for event to process so that a hacker
// wait a minimum of seconds for type to process so that a hacker
// cannot flood with failed logins and overwhelm the queue and not have notBefore updated to block next requests
// todo failure HTTP responses should be queued via async HTTP
event.latch.await(5, TimeUnit.SECONDS);
@@ -0,0 +1,57 @@
package org.keycloak.services.managers;
import org.jboss.logging.Logger;
import org.keycloak.ClientConnection;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.EventStoreProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class EventsManager {
private Logger log = Logger.getLogger(EventsManager.class);
private RealmModel realm;
private KeycloakSession session;
private ClientConnection clientConnection;
public EventsManager(RealmModel realm, KeycloakSession session, ClientConnection clientConnection) {
this.realm = realm;
this.session = session;
this.clientConnection = clientConnection;
}
public EventBuilder createEventBuilder() {
List<EventListenerProvider> listeners = new LinkedList<EventListenerProvider>();
if (realm.isEventsEnabled()) {
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
if (eventStore != null) {
listeners.add(eventStore);
} else {
log.error("Events enabled, but no event store provider configured");
}
}
if (realm.getEventsListeners() != null) {
for (String id : realm.getEventsListeners()) {
EventListenerProvider listener = session.getProvider(EventListenerProvider.class, id);
if (listener != null) {
listeners.add(listener);
} else {
log.error("Event listener '" + id + "' registered, but provider not found");
}
}
}
return new EventBuilder(listeners, realm, clientConnection.getRemoteAddr());
}
}
@@ -19,7 +19,7 @@ import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.representations.idm.RealmAuditRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.timer.TimerProvider;
@@ -155,11 +155,11 @@ public class RealmManager {
return removed;
}
public void updateRealmAudit(RealmAuditRepresentation rep, RealmModel realm) {
realm.setAuditEnabled(rep.isAuditEnabled());
realm.setAuditExpiration(rep.getAuditExpiration() != null ? rep.getAuditExpiration() : 0);
if (rep.getAuditListeners() != null) {
realm.setAuditListeners(new HashSet<String>(rep.getAuditListeners()));
public void updateRealmEventsConfig(RealmEventsConfigRepresentation rep, RealmModel realm) {
realm.setEventsEnabled(rep.isEventsEnabled());
realm.setEventsExpiration(rep.getEventsExpiration() != null ? rep.getEventsExpiration() : 0);
if (rep.getEventsListeners() != null) {
realm.setEventsListeners(new HashSet<String>(rep.getEventsListeners()));
}
}
@@ -3,8 +3,8 @@ package org.keycloak.services.managers;
import org.jboss.logging.Logger;
import org.keycloak.ClientConnection;
import org.keycloak.OAuthErrorException;
import org.keycloak.audit.Audit;
import org.keycloak.audit.Details;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.Details;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider;
@@ -63,10 +63,10 @@ public class TokenManager {
return new AccessCode(realm, clientSession);
}
public AccessToken refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel client, String encodedRefreshToken, Audit audit) throws OAuthErrorException {
public AccessToken refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel client, String encodedRefreshToken, EventBuilder event) throws OAuthErrorException {
RefreshToken refreshToken = verifyRefreshToken(realm, encodedRefreshToken);
audit.user(refreshToken.getSubject()).session(refreshToken.getSessionState()).detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
event.user(refreshToken.getSubject()).session(refreshToken.getSessionState()).detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
UserModel user = session.users().getUserById(refreshToken.getSubject(), realm);
if (user == null) {
@@ -290,8 +290,8 @@ public class TokenManager {
return encodedToken;
}
public AccessTokenResponseBuilder responseBuilder(RealmModel realm, ClientModel client, Audit audit) {
return new AccessTokenResponseBuilder(realm, client, audit);
public AccessTokenResponseBuilder responseBuilder(RealmModel realm, ClientModel client, EventBuilder event) {
return new AccessTokenResponseBuilder(realm, client, event);
}
public class AccessTokenResponseBuilder {
@@ -300,12 +300,12 @@ public class TokenManager {
AccessToken accessToken;
RefreshToken refreshToken;
IDToken idToken;
Audit audit;
EventBuilder event;
public AccessTokenResponseBuilder(RealmModel realm, ClientModel client, Audit audit) {
public AccessTokenResponseBuilder(RealmModel realm, ClientModel client, EventBuilder event) {
this.realm = realm;
this.client = client;
this.audit = audit;
this.event = event;
}
public AccessTokenResponseBuilder accessToken(AccessToken accessToken) {
@@ -379,14 +379,14 @@ public class TokenManager {
public AccessTokenResponse build() {
if (accessToken != null) {
audit.detail(Details.TOKEN_ID, accessToken.getId());
event.detail(Details.TOKEN_ID, accessToken.getId());
}
if (refreshToken != null) {
if (audit.getEvent().getDetails().containsKey(Details.REFRESH_TOKEN_ID)) {
audit.detail(Details.UPDATED_REFRESH_TOKEN_ID, refreshToken.getId());
if (event.getEvent().getDetails().containsKey(Details.REFRESH_TOKEN_ID)) {
event.detail(Details.UPDATED_REFRESH_TOKEN_ID, refreshToken.getId());
} else {
audit.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
event.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
}
}
@@ -28,11 +28,11 @@ import org.keycloak.ClientConnection;
import org.keycloak.OAuth2Constants;
import org.keycloak.account.AccountPages;
import org.keycloak.account.AccountProvider;
import org.keycloak.audit.Audit;
import org.keycloak.audit.AuditProvider;
import org.keycloak.audit.Details;
import org.keycloak.audit.Event;
import org.keycloak.audit.EventType;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventStoreProvider;
import org.keycloak.events.Details;
import org.keycloak.events.Event;
import org.keycloak.events.EventType;
import org.keycloak.models.AccountRoles;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
@@ -92,18 +92,18 @@ public class AccountService {
private static final Logger logger = Logger.getLogger(AccountService.class);
private static final EventType[] AUDIT_EVENTS = {EventType.LOGIN, EventType.LOGOUT, EventType.REGISTER, EventType.REMOVE_SOCIAL_LINK, EventType.REMOVE_TOTP, EventType.SEND_RESET_PASSWORD,
private static final EventType[] LOG_EVENTS = {EventType.LOGIN, EventType.LOGOUT, EventType.REGISTER, EventType.REMOVE_SOCIAL_LINK, EventType.REMOVE_TOTP, EventType.SEND_RESET_PASSWORD,
EventType.SEND_VERIFY_EMAIL, EventType.SOCIAL_LINK, EventType.UPDATE_EMAIL, EventType.UPDATE_PASSWORD, EventType.UPDATE_PROFILE, EventType.UPDATE_TOTP, EventType.VERIFY_EMAIL};
private static final Set<String> AUDIT_DETAILS = new HashSet<String>();
private static final Set<String> LOG_DETAILS = new HashSet<String>();
static {
AUDIT_DETAILS.add(Details.UPDATED_EMAIL);
AUDIT_DETAILS.add(Details.EMAIL);
AUDIT_DETAILS.add(Details.PREVIOUS_EMAIL);
AUDIT_DETAILS.add(Details.USERNAME);
AUDIT_DETAILS.add(Details.REMEMBER_ME);
AUDIT_DETAILS.add(Details.REGISTER_METHOD);
AUDIT_DETAILS.add(Details.AUTH_METHOD);
LOG_DETAILS.add(Details.UPDATED_EMAIL);
LOG_DETAILS.add(Details.EMAIL);
LOG_DETAILS.add(Details.PREVIOUS_EMAIL);
LOG_DETAILS.add(Details.USERNAME);
LOG_DETAILS.add(Details.REMEMBER_ME);
LOG_DETAILS.add(Details.REGISTER_METHOD);
LOG_DETAILS.add(Details.AUTH_METHOD);
}
private RealmModel realm;
@@ -125,20 +125,20 @@ public class AccountService {
private final AppAuthManager authManager;
private final ApplicationModel application;
private Audit audit;
private EventBuilder event;
private AccountProvider account;
private Auth auth;
private AuditProvider auditProvider;
private EventStoreProvider eventStore;
public AccountService(RealmModel realm, ApplicationModel application, Audit audit) {
public AccountService(RealmModel realm, ApplicationModel application, EventBuilder event) {
this.realm = realm;
this.application = application;
this.audit = audit;
this.event = event;
this.authManager = new AppAuthManager();
}
public void init() {
auditProvider = session.getProvider(AuditProvider.class);
eventStore = session.getProvider(EventStoreProvider.class);
account = session.getProvider(AccountProvider.class).setRealm(realm).setUriInfo(uriInfo);
@@ -170,10 +170,10 @@ public class AccountService {
}
boolean auditEnabled = auditProvider != null && realm.isAuditEnabled();
boolean eventsEnabled = eventStore != null && realm.isEventsEnabled();
// todo find out from federation if password is updatable
account.setFeatures(realm.isSocial(), auditEnabled, true);
account.setFeatures(realm.isSocial(), eventsEnabled, true);
}
public static UriBuilder accountServiceBaseUrl(UriInfo uriInfo) {
@@ -282,12 +282,12 @@ public class AccountService {
@GET
public Response logPage() {
if (auth != null) {
List<Event> events = auditProvider.createQuery().event(AUDIT_EVENTS).user(auth.getUser().getId()).maxResults(30).getResultList();
List<Event> events = eventStore.createQuery().type(LOG_EVENTS).user(auth.getUser().getId()).maxResults(30).getResultList();
for (Event e : events) {
if (e.getDetails() != null) {
Iterator<Map.Entry<String, String>> itr = e.getDetails().entrySet().iterator();
while (itr.hasNext()) {
if (!AUDIT_DETAILS.contains(itr.next().getKey())) {
if (!LOG_DETAILS.contains(itr.next().getKey())) {
itr.remove();
}
}
@@ -353,11 +353,11 @@ public class AccountService {
user.setEmail(formData.getFirst("email"));
audit.event(EventType.UPDATE_PROFILE).client(auth.getClient()).user(auth.getUser()).success();
event.event(EventType.UPDATE_PROFILE).client(auth.getClient()).user(auth.getUser()).success();
if (emailChanged) {
user.setEmailVerified(false);
audit.clone().event(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, oldEmail).detail(Details.UPDATED_EMAIL, email).success();
event.clone().event(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, oldEmail).detail(Details.UPDATED_EMAIL, email).success();
}
setReferrerOnPage();
return account.setSuccess("accountUpdated").createResponse(AccountPages.ACCOUNT);
@@ -379,7 +379,7 @@ public class AccountService {
UserModel user = auth.getUser();
user.setTotp(false);
audit.event(EventType.REMOVE_TOTP).client(auth.getClient()).user(auth.getUser()).success();
event.event(EventType.REMOVE_TOTP).client(auth.getClient()).user(auth.getUser()).success();
setReferrerOnPage();
return account.setSuccess("successTotpRemoved").createResponse(AccountPages.TOTP);
@@ -455,7 +455,7 @@ public class AccountService {
user.setTotp(true);
audit.event(EventType.UPDATE_TOTP).client(auth.getClient()).user(auth.getUser()).success();
event.event(EventType.UPDATE_TOTP).client(auth.getClient()).user(auth.getUser()).success();
setReferrerOnPage();
return account.setSuccess("successTotp").createResponse(AccountPages.TOTP);
@@ -525,7 +525,7 @@ public class AccountService {
return account.setError(ape.getMessage()).createResponse(AccountPages.PASSWORD);
}
audit.event(EventType.UPDATE_PASSWORD).client(auth.getClient()).user(auth.getUser()).success();
event.event(EventType.UPDATE_PASSWORD).client(auth.getClient()).user(auth.getUser()).success();
setReferrerOnPage();
return account.setSuccess("accountPasswordUpdated").createResponse(AccountPages.PASSWORD);
@@ -588,7 +588,7 @@ public class AccountService {
logger.debugv("Social provider {0} removed successfully from user {1}", providerId, user.getUsername());
audit.event(EventType.REMOVE_SOCIAL_LINK).client(auth.getClient()).user(auth.getUser())
event.event(EventType.REMOVE_SOCIAL_LINK).client(auth.getClient()).user(auth.getUser())
.detail(Details.USERNAME, link.getSocialUserId() + "@" + link.getSocialProvider())
.success();
@@ -19,7 +19,7 @@ import org.keycloak.services.managers.UsersSyncManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.services.scheduled.ClearExpiredAuditEvents;
import org.keycloak.services.scheduled.ClearExpiredEvents;
import org.keycloak.services.scheduled.ClearExpiredUserSessions;
import org.keycloak.services.scheduled.ScheduledTaskRunner;
import org.keycloak.services.util.JsonConfigProvider;
@@ -147,7 +147,7 @@ public class KeycloakApplication extends Application {
long interval = Config.scope("scheduled").getLong("interval", 60L) * 1000;
TimerProvider timer = sessionFactory.create().getProvider(TimerProvider.class);
timer.schedule(new ScheduledTaskRunner(sessionFactory, new ClearExpiredAuditEvents()), interval, "ClearExpiredAuditEvents");
timer.schedule(new ScheduledTaskRunner(sessionFactory, new ClearExpiredEvents()), interval, "ClearExpiredEvents");
timer.schedule(new ScheduledTaskRunner(sessionFactory, new ClearExpiredUserSessions()), interval, "ClearExpiredUserSessions");
new UsersSyncManager().bootstrapPeriodic(sessionFactory, timer);
}
@@ -6,13 +6,13 @@ import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.ClientConnection;
import org.keycloak.audit.Audit;
import org.keycloak.events.EventBuilder;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.AuditManager;
import org.keycloak.services.managers.EventsManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.BruteForceProtector;
import org.keycloak.services.managers.RealmManager;
@@ -140,9 +140,9 @@ public class RealmsResource {
public TokenService getTokenService(final @PathParam("realm") String name) {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = locateRealm(name, realmManager);
Audit audit = new AuditManager(realm, session, clientConnection).createAudit();
EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder();
AuthenticationManager authManager = new AuthenticationManager(protector);
TokenService tokenService = new TokenService(realm, tokenManager, audit, authManager);
TokenService tokenService = new TokenService(realm, tokenManager, event, authManager);
ResteasyProviderFactory.getInstance().injectProperties(tokenService);
//resourceContext.initResource(tokenService);
return tokenService;
@@ -167,8 +167,8 @@ public class RealmsResource {
throw new NotFoundException("account management not enabled");
}
Audit audit = new AuditManager(realm, session, clientConnection).createAudit();
AccountService accountService = new AccountService(realm, application, audit);
EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder();
AccountService accountService = new AccountService(realm, application, event);
ResteasyProviderFactory.getInstance().injectProperties(accountService);
//resourceContext.initResource(accountService);
accountService.init();
@@ -25,10 +25,10 @@ import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
import org.keycloak.OAuth2Constants;
import org.keycloak.audit.Audit;
import org.keycloak.audit.Details;
import org.keycloak.audit.Errors;
import org.keycloak.audit.EventType;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventType;
import org.keycloak.email.EmailException;
import org.keycloak.email.EmailProvider;
import org.keycloak.login.LoginFormsProvider;
@@ -94,12 +94,12 @@ public class RequiredActionsService {
private TokenManager tokenManager;
private Audit audit;
private EventBuilder event;
public RequiredActionsService(RealmModel realm, TokenManager tokenManager, Audit audit) {
public RequiredActionsService(RealmModel realm, TokenManager tokenManager, EventBuilder event) {
this.realm = realm;
this.tokenManager = tokenManager;
this.audit = audit;
this.event = event;
}
@Path("profile")
@@ -113,7 +113,7 @@ public class RequiredActionsService {
UserModel user = getUser(accessCode);
initAudit(accessCode);
initEvent(accessCode);
String error = Validation.validateUpdateProfileForm(formData);
if (error != null) {
@@ -131,10 +131,10 @@ public class RequiredActionsService {
user.removeRequiredAction(RequiredAction.UPDATE_PROFILE);
audit.clone().event(EventType.UPDATE_PROFILE).success();
event.clone().event(EventType.UPDATE_PROFILE).success();
if (emailChanged) {
user.setEmailVerified(false);
audit.clone().event(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, oldEmail).detail(Details.UPDATED_EMAIL, email).success();
event.clone().event(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, oldEmail).detail(Details.UPDATED_EMAIL, email).success();
}
return redirectOauth(user, accessCode);
@@ -151,7 +151,7 @@ public class RequiredActionsService {
UserModel user = getUser(accessCode);
initAudit(accessCode);
initEvent(accessCode);
String totp = formData.getFirst("totp");
String totpSecret = formData.getFirst("totpSecret");
@@ -172,7 +172,7 @@ public class RequiredActionsService {
user.removeRequiredAction(RequiredAction.CONFIGURE_TOTP);
audit.clone().event(EventType.UPDATE_TOTP).success();
event.clone().event(EventType.UPDATE_TOTP).success();
return redirectOauth(user, accessCode);
}
@@ -188,7 +188,7 @@ public class RequiredActionsService {
UserModel user = getUser(accessCode);
initAudit(accessCode);
initEvent(accessCode);
String passwordNew = formData.getFirst("password-new");
String passwordConfirm = formData.getFirst("password-confirm");
@@ -208,7 +208,7 @@ public class RequiredActionsService {
user.removeRequiredAction(RequiredAction.UPDATE_PASSWORD);
audit.clone().event(EventType.UPDATE_PASSWORD).success();
event.clone().event(EventType.UPDATE_PASSWORD).success();
// Redirect to account management to login if password reset was initiated by admin
if (accessCode.getSessionState() == null) {
@@ -230,13 +230,13 @@ public class RequiredActionsService {
UserModel user = getUser(accessCode);
initAudit(accessCode);
initEvent(accessCode);
user.setEmailVerified(true);
user.removeRequiredAction(RequiredAction.VERIFY_EMAIL);
audit.clone().event(EventType.VERIFY_EMAIL).detail(Details.EMAIL, accessCode.getUser().getEmail()).success();
event.clone().event(EventType.VERIFY_EMAIL).detail(Details.EMAIL, accessCode.getUser().getEmail()).success();
return redirectOauth(user, accessCode);
} else {
@@ -245,7 +245,7 @@ public class RequiredActionsService {
return unauthorized();
}
initAudit(accessCode);
initEvent(accessCode);
return Flows.forms(session, realm, null, uriInfo).setAccessCode(accessCode.getCode()).setUser(accessCode.getUser())
.createResponse(RequiredAction.VERIFY_EMAIL);
@@ -290,7 +290,7 @@ public class RequiredActionsService {
"Login requester not enabled.");
}
audit.event(EventType.SEND_RESET_PASSWORD).client(clientId)
event.event(EventType.SEND_RESET_PASSWORD).client(clientId)
.detail(Details.REDIRECT_URI, redirect)
.detail(Details.RESPONSE_TYPE, "code")
.detail(Details.AUTH_METHOD, "form")
@@ -302,10 +302,10 @@ public class RequiredActionsService {
}
if (user == null) {
audit.error(Errors.USER_NOT_FOUND);
event.error(Errors.USER_NOT_FOUND);
} else {
UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, clientConnection.getRemoteAddr(), "form", false);
audit.session(userSession);
event.session(userSession);
AccessCode accessCode = tokenManager.createAccessCode(scopeParam, state, redirect, session, realm, client, user, userSession);
accessCode.setRequiredAction(RequiredAction.UPDATE_PASSWORD);
@@ -319,7 +319,7 @@ public class RequiredActionsService {
this.session.getProvider(EmailProvider.class).setRealm(realm).setUser(user).sendPasswordReset(link, expiration);
audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success();
event.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success();
} catch (EmailException e) {
logger.error("Failed to send password reset email", e);
return Flows.forms(this.session, realm, client, uriInfo).setError("emailSendError").createErrorPage();
@@ -375,17 +375,17 @@ public class RequiredActionsService {
AuthenticationManager.logout(session, realm, userSession, uriInfo, clientConnection);
return Flows.oauth(this.session, realm, request, uriInfo, clientConnection, authManager, tokenManager).redirectError(accessCode.getClient(), "access_denied", accessCode.getState(), accessCode.getRedirectUri());
}
audit.session(userSession);
event.session(userSession);
audit.success();
event.success();
return Flows.oauth(this.session, realm, request, uriInfo, clientConnection, authManager, tokenManager).redirectAccessCode(accessCode,
userSession, accessCode.getState(), accessCode.getRedirectUri());
}
}
private void initAudit(AccessCode accessCode) {
audit.event(EventType.LOGIN).client(accessCode.getClient())
private void initEvent(AccessCode accessCode) {
event.event(EventType.LOGIN).client(accessCode.getClient())
.user(accessCode.getUser())
.session(accessCode.getSessionState())
.detail(Details.CODE_ID, accessCode.getCodeId())
@@ -395,10 +395,10 @@ public class RequiredActionsService {
UserSessionModel userSession = accessCode.getSessionState() != null ? session.sessions().getUserSession(realm, accessCode.getSessionState()) : null;
if (userSession != null) {
audit.detail(Details.AUTH_METHOD, userSession.getAuthMethod());
audit.detail(Details.USERNAME, userSession.getLoginUsername());
event.detail(Details.AUTH_METHOD, userSession.getAuthMethod());
event.detail(Details.USERNAME, userSession.getLoginUsername());
if (userSession.isRememberMe()) {
audit.detail(Details.REMEMBER_ME, "true");
event.detail(Details.REMEMBER_ME, "true");
}
}
}
@@ -26,12 +26,11 @@ import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
import org.keycloak.OAuth2Constants;
import org.keycloak.audit.Audit;
import org.keycloak.audit.Details;
import org.keycloak.audit.Errors;
import org.keycloak.audit.EventType;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventType;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.AccountRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
@@ -42,13 +41,12 @@ import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.services.managers.AuditManager;
import org.keycloak.services.managers.EventsManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthFlows;
import org.keycloak.services.resources.flows.OAuthRedirect;
import org.keycloak.services.resources.flows.Urls;
import org.keycloak.social.AuthCallback;
import org.keycloak.social.SocialAccessDeniedException;
@@ -124,7 +122,7 @@ public class SocialResource {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealmByName(realmName);
Audit audit = new AuditManager(realm, session, clientConnection).createAudit()
EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder()
.event(EventType.LOGIN)
.detail(Details.RESPONSE_TYPE, initialRequest.get(OAuth2Constants.RESPONSE_TYPE))
.detail(Details.AUTH_METHOD, authMethod);
@@ -133,7 +131,7 @@ public class SocialResource {
OAuthFlows oauth = Flows.oauth(session, realm, request, uriInfo, clientConnection, authManager, tokenManager);
if (!realm.isEnabled()) {
audit.error(Errors.REALM_DISABLED);
event.error(Errors.REALM_DISABLED);
return oauth.forwardToSecurityFailure("Realm not enabled.");
}
@@ -143,15 +141,15 @@ public class SocialResource {
String state = initialRequest.get(OAuth2Constants.STATE);
String responseType = initialRequest.get(OAuth2Constants.RESPONSE_TYPE);
audit.client(clientId).detail(Details.REDIRECT_URI, redirectUri);
event.client(clientId).detail(Details.REDIRECT_URI, redirectUri);
ClientModel client = realm.findClient(clientId);
if (client == null) {
audit.error(Errors.CLIENT_NOT_FOUND);
event.error(Errors.CLIENT_NOT_FOUND);
return oauth.forwardToSecurityFailure("Unknown login requester.");
}
if (!client.isEnabled()) {
audit.error(Errors.CLIENT_DISABLED);
event.error(Errors.CLIENT_DISABLED);
return oauth.forwardToSecurityFailure("Login requester not enabled.");
}
@@ -176,14 +174,14 @@ public class SocialResource {
queryParms.putSingle(OAuth2Constants.REDIRECT_URI, redirectUri);
queryParms.putSingle(OAuth2Constants.RESPONSE_TYPE, responseType);
audit.error(Errors.REJECTED_BY_USER);
event.error(Errors.REJECTED_BY_USER);
return Flows.forms(session, realm, client, uriInfo).setQueryParams(queryParms).setWarning("Access denied").createLogin();
} catch (SocialProviderException e) {
logger.error("Failed to process social callback", e);
return oauth.forwardToSecurityFailure("Failed to process social callback");
}
audit.detail(Details.USERNAME, socialUser.getId() + "@" + provider.getId());
event.detail(Details.USERNAME, socialUser.getId() + "@" + provider.getId());
try {
SocialLinkModel socialLink = new SocialLinkModel(provider.getId(), socialUser.getId(), socialUser.getUsername());
@@ -194,32 +192,32 @@ public class SocialResource {
if (userId != null) {
UserModel authenticatedUser = session.users().getUserById(userId, realm);
audit.event(EventType.SOCIAL_LINK).user(userId);
event.event(EventType.SOCIAL_LINK).user(userId);
if (user != null) {
audit.error(Errors.SOCIAL_ID_IN_USE);
event.error(Errors.SOCIAL_ID_IN_USE);
return oauth.forwardToSecurityFailure("This social account is already linked to other user");
}
if (!authenticatedUser.isEnabled()) {
audit.error(Errors.USER_DISABLED);
event.error(Errors.USER_DISABLED);
return oauth.forwardToSecurityFailure("User is disabled");
}
if (!authenticatedUser.hasRole(realm.getApplicationByName(Constants.ACCOUNT_MANAGEMENT_APP).getRole(AccountRoles.MANAGE_ACCOUNT))) {
audit.error(Errors.NOT_ALLOWED);
event.error(Errors.NOT_ALLOWED);
return oauth.forwardToSecurityFailure("Insufficient permissions to link social account");
}
if (redirectUri == null) {
audit.error(Errors.INVALID_REDIRECT_URI);
event.error(Errors.INVALID_REDIRECT_URI);
return oauth.forwardToSecurityFailure("Unknown redirectUri");
}
session.users().addSocialLink(realm, authenticatedUser, socialLink);
logger.debugv("Social provider {0} linked with user {1}", provider.getId(), authenticatedUser.getUsername());
audit.success();
event.success();
return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build();
}
@@ -236,26 +234,26 @@ public class SocialResource {
session.users().addSocialLink(realm, user, socialLink);
audit.clone().user(user).event(EventType.REGISTER)
event.clone().user(user).event(EventType.REGISTER)
.detail(Details.REGISTER_METHOD, "social@" + provider.getId())
.detail(Details.EMAIL, socialUser.getEmail())
.removeDetail("auth_method")
.success();
}
audit.user(user);
event.user(user);
if (!user.isEnabled()) {
audit.error(Errors.USER_DISABLED);
event.error(Errors.USER_DISABLED);
return oauth.forwardToSecurityFailure("Your account is not enabled.");
}
String username = socialLink.getSocialUserId() + "@" + socialLink.getSocialProvider();
UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, clientConnection.getRemoteAddr(), authMethod, false);
audit.session(userSession);
event.session(userSession);
Response response = oauth.processAccessCode(scope, state, redirectUri, client, user, userSession, audit);
Response response = oauth.processAccessCode(scope, state, redirectUri, client, user, userSession, event);
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
@@ -275,7 +273,7 @@ public class SocialResource {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealmByName(realmName);
Audit audit = new AuditManager(realm, session, clientConnection).createAudit()
EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder()
.event(EventType.LOGIN).client(clientId)
.detail(Details.REDIRECT_URI, redirectUri)
.detail(Details.RESPONSE_TYPE, "code")
@@ -283,23 +281,23 @@ public class SocialResource {
SocialProvider provider = SocialLoader.load(providerId);
if (provider == null) {
audit.error(Errors.SOCIAL_PROVIDER_NOT_FOUND);
event.error(Errors.SOCIAL_PROVIDER_NOT_FOUND);
return Flows.forms(session, realm, null, uriInfo).setError("Social provider not found").createErrorPage();
}
ClientModel client = realm.findClient(clientId);
if (client == null) {
audit.error(Errors.CLIENT_NOT_FOUND);
event.error(Errors.CLIENT_NOT_FOUND);
return Flows.forms(session, realm, null, uriInfo).setError("Unknown login requester.").createErrorPage();
}
if (!client.isEnabled()) {
audit.error(Errors.CLIENT_DISABLED);
event.error(Errors.CLIENT_DISABLED);
return Flows.forms(session, realm, null, uriInfo).setError("Login requester not enabled.").createErrorPage();
}
redirectUri = TokenService.verifyRedirectUri(uriInfo, redirectUri, realm, client);
if (redirectUri == null) {
audit.error(Errors.INVALID_REDIRECT_URI);
event.error(Errors.INVALID_REDIRECT_URI);
return Flows.forms(session, realm, null, uriInfo).setError("Invalid redirect_uri.").createErrorPage();
}
@@ -13,10 +13,10 @@ import org.keycloak.ClientConnection;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
import org.keycloak.RSATokenVerifier;
import org.keycloak.audit.Audit;
import org.keycloak.audit.Details;
import org.keycloak.audit.Errors;
import org.keycloak.audit.EventType;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventType;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
@@ -85,7 +85,7 @@ public class TokenService {
protected RealmModel realm;
protected TokenManager tokenManager;
private Audit audit;
private EventBuilder event;
protected AuthenticationManager authManager;
@Context
@@ -112,10 +112,10 @@ public class TokenService {
private ResourceAdminManager resourceAdminManager = new ResourceAdminManager();
public TokenService(RealmModel realm, TokenManager tokenManager, Audit audit, AuthenticationManager authManager) {
public TokenService(RealmModel realm, TokenManager tokenManager, EventBuilder event, AuthenticationManager authManager) {
this.realm = realm;
this.tokenManager = tokenManager;
this.audit = audit;
this.event = event;
this.authManager = authManager;
}
@@ -232,22 +232,22 @@ public class TokenService {
return createError("not_enabled", "Direct Grant REST API not enabled", Response.Status.FORBIDDEN);
}
audit.event(EventType.LOGIN).detail(Details.AUTH_METHOD, "oauth_credentials").detail(Details.RESPONSE_TYPE, "token");
event.event(EventType.LOGIN).detail(Details.AUTH_METHOD, "oauth_credentials").detail(Details.RESPONSE_TYPE, "token");
String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) {
audit.error(Errors.USERNAME_MISSING);
event.error(Errors.USERNAME_MISSING);
throw new UnauthorizedException("No username");
}
audit.detail(Details.USERNAME, username);
event.detail(Details.USERNAME, username);
UserModel user = session.users().getUserByUsername(username, realm);
if (user != null) audit.user(user);
if (user != null) event.user(user);
ClientModel client = authorizeClient(authorizationHeader, form, audit);
ClientModel client = authorizeClient(authorizationHeader, form, event);
if (!realm.isEnabled()) {
audit.error(Errors.REALM_DISABLED);
event.error(Errors.REALM_DISABLED);
return createError("realm_disabled", "Realm is disabled", Response.Status.UNAUTHORIZED);
}
@@ -262,21 +262,21 @@ public class TokenService {
err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, "invalid_grant");
err.put(OAuth2Constants.ERROR_DESCRIPTION, "AccountProvider temporarily disabled");
audit.error(Errors.USER_TEMPORARILY_DISABLED);
event.error(Errors.USER_TEMPORARILY_DISABLED);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
case ACCOUNT_DISABLED:
err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, "invalid_grant");
err.put(OAuth2Constants.ERROR_DESCRIPTION, "AccountProvider disabled");
audit.error(Errors.USER_DISABLED);
event.error(Errors.USER_DISABLED);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
default:
err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, "invalid_grant");
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Invalid user credentials");
audit.error(Errors.INVALID_USER_CREDENTIALS);
event.error(Errors.INVALID_USER_CREDENTIALS);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
}
@@ -284,15 +284,15 @@ public class TokenService {
String scope = form.getFirst(OAuth2Constants.SCOPE);
UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, clientConnection.getRemoteAddr(), "oauth_credentials", false);
audit.session(userSession);
event.session(userSession);
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, audit)
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event)
.generateAccessToken(scope, client, user, userSession)
.generateRefreshToken()
.generateIDToken()
.build();
audit.success();
event.success();
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
}
@@ -311,7 +311,7 @@ public class TokenService {
if (!checkSsl()) {
return createError("https_required", "HTTPS required", Response.Status.FORBIDDEN);
}
audit.event(EventType.VALIDATE_ACCESS_TOKEN);
event.event(EventType.VALIDATE_ACCESS_TOKEN);
AccessToken token = null;
try {
token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName());
@@ -319,11 +319,11 @@ public class TokenService {
Map<String, String> err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Token invalid");
audit.error(Errors.INVALID_TOKEN);
event.error(Errors.INVALID_TOKEN);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
}
audit.user(token.getSubject()).session(token.getSessionState()).detail(Details.VALIDATE_ACCESS_TOKEN, token.getId());
event.user(token.getSubject()).session(token.getSessionState()).detail(Details.VALIDATE_ACCESS_TOKEN, token.getId());
if (token.isExpired()
|| token.getIssuedAt() < realm.getNotBefore()
@@ -331,7 +331,7 @@ public class TokenService {
Map<String, String> err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Token expired");
audit.error(Errors.INVALID_TOKEN);
event.error(Errors.INVALID_TOKEN);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
}
@@ -342,7 +342,7 @@ public class TokenService {
Map<String, String> err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
err.put(OAuth2Constants.ERROR_DESCRIPTION, "User does not exist");
audit.error(Errors.USER_NOT_FOUND);
event.error(Errors.USER_NOT_FOUND);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
}
@@ -351,7 +351,7 @@ public class TokenService {
Map<String, String> err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
err.put(OAuth2Constants.ERROR_DESCRIPTION, "User disabled");
audit.error(Errors.USER_DISABLED);
event.error(Errors.USER_DISABLED);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
}
@@ -361,7 +361,7 @@ public class TokenService {
Map<String, String> err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Expired session");
audit.error(Errors.USER_SESSION_NOT_FOUND);
event.error(Errors.USER_SESSION_NOT_FOUND);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
}
@@ -371,7 +371,7 @@ public class TokenService {
Map<String, String> err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_CLIENT);
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Issued for client no longer exists");
audit.error(Errors.CLIENT_NOT_FOUND);
event.error(Errors.CLIENT_NOT_FOUND);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
@@ -381,7 +381,7 @@ public class TokenService {
Map<String, String> err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_CLIENT);
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Issued for client no longer exists");
audit.error(Errors.INVALID_TOKEN);
event.error(Errors.INVALID_TOKEN);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
}
@@ -392,7 +392,7 @@ public class TokenService {
Map<String, String> err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_SCOPE);
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Role mappings have changed");
audit.error(Errors.INVALID_TOKEN);
event.error(Errors.INVALID_TOKEN);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
.build();
@@ -424,34 +424,34 @@ public class TokenService {
return createError("https_required", "HTTPS required", Response.Status.FORBIDDEN);
}
audit.event(EventType.REFRESH_TOKEN);
event.event(EventType.REFRESH_TOKEN);
ClientModel client = authorizeClient(authorizationHeader, form, audit);
ClientModel client = authorizeClient(authorizationHeader, form, event);
String refreshToken = form.getFirst(OAuth2Constants.REFRESH_TOKEN);
if (refreshToken == null) {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_REQUEST);
error.put(OAuth2Constants.ERROR_DESCRIPTION, "No refresh token");
audit.error(Errors.INVALID_TOKEN);
event.error(Errors.INVALID_TOKEN);
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
}
AccessToken accessToken;
try {
accessToken = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, audit);
accessToken = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, event);
} catch (OAuthErrorException e) {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, e.getError());
if (e.getDescription() != null) error.put(OAuth2Constants.ERROR_DESCRIPTION, e.getDescription());
audit.error(Errors.INVALID_TOKEN);
event.error(Errors.INVALID_TOKEN);
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
}
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, audit)
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event)
.accessToken(accessToken)
.generateIDToken()
.generateRefreshToken().build();
audit.success();
event.success();
return Cors.add(request, Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
}
@@ -477,14 +477,14 @@ public class TokenService {
String rememberMe = formData.getFirst("rememberMe");
boolean remember = rememberMe != null && rememberMe.equalsIgnoreCase("on");
audit.event(EventType.LOGIN).client(clientId)
event.event(EventType.LOGIN).client(clientId)
.detail(Details.REDIRECT_URI, redirect)
.detail(Details.RESPONSE_TYPE, "code")
.detail(Details.AUTH_METHOD, "form")
.detail(Details.USERNAME, username);
if (remember) {
audit.detail(Details.REMEMBER_ME, "true");
event.detail(Details.REMEMBER_ME, "true");
}
OAuthFlows oauth = Flows.oauth(session, realm, request, uriInfo, clientConnection, authManager, tokenManager);
@@ -494,27 +494,27 @@ public class TokenService {
}
if (!realm.isEnabled()) {
audit.error(Errors.REALM_DISABLED);
event.error(Errors.REALM_DISABLED);
return oauth.forwardToSecurityFailure("Realm not enabled.");
}
ClientModel client = realm.findClient(clientId);
if (client == null) {
audit.error(Errors.CLIENT_NOT_FOUND);
event.error(Errors.CLIENT_NOT_FOUND);
return oauth.forwardToSecurityFailure("Unknown login requester.");
}
if (!client.isEnabled()) {
audit.error(Errors.CLIENT_NOT_FOUND);
event.error(Errors.CLIENT_NOT_FOUND);
return oauth.forwardToSecurityFailure("Login requester not enabled.");
}
redirect = verifyRedirectUri(uriInfo, redirect, realm, client);
if (redirect == null) {
audit.error(Errors.INVALID_REDIRECT_URI);
event.error(Errors.INVALID_REDIRECT_URI);
return oauth.forwardToSecurityFailure("Invalid redirect_uri.");
}
if (formData.containsKey("cancel")) {
audit.error(Errors.REJECTED_BY_USER);
event.error(Errors.REJECTED_BY_USER);
return oauth.redirectError(client, "access_denied", state, redirect);
}
@@ -528,36 +528,36 @@ public class TokenService {
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(session, realm, username);
if (user != null) {
audit.user(user);
event.user(user);
}
switch (status) {
case SUCCESS:
case ACTIONS_REQUIRED:
UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, clientConnection.getRemoteAddr(), "form", remember);
audit.session(userSession);
event.session(userSession);
return oauth.processAccessCode(scopeParam, state, redirect, client, user, userSession, audit);
return oauth.processAccessCode(scopeParam, state, redirect, client, user, userSession, event);
case ACCOUNT_TEMPORARILY_DISABLED:
audit.error(Errors.USER_TEMPORARILY_DISABLED);
event.error(Errors.USER_TEMPORARILY_DISABLED);
return Flows.forms(this.session, realm, client, uriInfo).setError(Messages.ACCOUNT_TEMPORARILY_DISABLED).setFormData(formData).createLogin();
case ACCOUNT_DISABLED:
audit.error(Errors.USER_DISABLED);
event.error(Errors.USER_DISABLED);
return Flows.forms(this.session, realm, client, uriInfo).setError(Messages.ACCOUNT_DISABLED).setFormData(formData).createLogin();
case MISSING_TOTP:
return Flows.forms(this.session, realm, client, uriInfo).setFormData(formData).createLoginTotp();
case INVALID_USER:
audit.error(Errors.USER_NOT_FOUND);
event.error(Errors.USER_NOT_FOUND);
return Flows.forms(this.session, realm, client, uriInfo).setError(Messages.INVALID_USER).setFormData(formData).createLogin();
default:
audit.error(Errors.INVALID_USER_CREDENTIALS);
event.error(Errors.INVALID_USER_CREDENTIALS);
return Flows.forms(this.session, realm, client, uriInfo).setError(Messages.INVALID_USER).setFormData(formData).createLogin();
}
}
@Path("auth/request/login-actions")
public RequiredActionsService getRequiredActionsService() {
RequiredActionsService service = new RequiredActionsService(realm, tokenManager, audit);
RequiredActionsService service = new RequiredActionsService(realm, tokenManager, event);
ResteasyProviderFactory.getInstance().injectProperties(service);
//resourceContext.initResource(service);
@@ -584,7 +584,7 @@ public class TokenService {
String username = formData.getFirst("username");
String email = formData.getFirst("email");
audit.event(EventType.REGISTER).client(clientId)
event.event(EventType.REGISTER).client(clientId)
.detail(Details.REDIRECT_URI, redirect)
.detail(Details.RESPONSE_TYPE, "code")
.detail(Details.USERNAME, username)
@@ -594,28 +594,28 @@ public class TokenService {
OAuthFlows oauth = Flows.oauth(session, realm, request, uriInfo, clientConnection, authManager, tokenManager);
if (!realm.isEnabled()) {
audit.error(Errors.REALM_DISABLED);
event.error(Errors.REALM_DISABLED);
return oauth.forwardToSecurityFailure("Realm not enabled");
}
ClientModel client = realm.findClient(clientId);
if (client == null) {
audit.error(Errors.CLIENT_NOT_FOUND);
event.error(Errors.CLIENT_NOT_FOUND);
return oauth.forwardToSecurityFailure("Unknown login requester.");
}
if (!client.isEnabled()) {
audit.error(Errors.CLIENT_DISABLED);
event.error(Errors.CLIENT_DISABLED);
return oauth.forwardToSecurityFailure("Login requester not enabled.");
}
redirect = verifyRedirectUri(uriInfo, redirect, realm, client);
if (redirect == null) {
audit.error(Errors.INVALID_REDIRECT_URI);
event.error(Errors.INVALID_REDIRECT_URI);
return oauth.forwardToSecurityFailure("Invalid redirect_uri.");
}
if (!realm.isRegistrationAllowed()) {
audit.error(Errors.REGISTRATION_DISABLED);
event.error(Errors.REGISTRATION_DISABLED);
return oauth.forwardToSecurityFailure("Registration not allowed");
}
@@ -631,19 +631,19 @@ public class TokenService {
}
if (error != null) {
audit.error(Errors.INVALID_REGISTRATION);
event.error(Errors.INVALID_REGISTRATION);
return Flows.forms(session, realm, client, uriInfo).setError(error).setFormData(formData).createRegistration();
}
// Validate that user with this username doesn't exist in realm or any federation provider
if (session.users().getUserByUsername(username, realm) != null) {
audit.error(Errors.USERNAME_IN_USE);
event.error(Errors.USERNAME_IN_USE);
return Flows.forms(session, realm, client, uriInfo).setError(Messages.USERNAME_EXISTS).setFormData(formData).createRegistration();
}
// Validate that user with this email doesn't exist in realm or any federation provider
if (session.users().getUserByEmail(email, realm) != null) {
audit.error(Errors.EMAIL_IN_USE);
event.error(Errors.EMAIL_IN_USE);
return Flows.forms(session, realm, client, uriInfo).setError(Messages.EMAIL_EXISTS).setFormData(formData).createRegistration();
}
@@ -676,8 +676,8 @@ public class TokenService {
}
}
audit.user(user).success();
audit.reset();
event.user(user).success();
event.reset();
return processLogin(clientId, scopeParam, state, redirect, formData);
}
@@ -714,10 +714,10 @@ public class TokenService {
throw new ForbiddenException("HTTPS required");
}
audit.event(EventType.CODE_TO_TOKEN);
event.event(EventType.CODE_TO_TOKEN);
if (!realm.isEnabled()) {
audit.error(Errors.REALM_DISABLED);
event.error(Errors.REALM_DISABLED);
throw new UnauthorizedException("Realm not enabled");
}
@@ -726,7 +726,7 @@ public class TokenService {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, "invalid_request");
error.put(OAuth2Constants.ERROR_DESCRIPTION, "code not specified");
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
throw new BadRequestException("Code not specified", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
}
@@ -735,39 +735,39 @@ public class TokenService {
String[] parts = code.split("\\.");
if (parts.length == 2) {
try {
audit.detail(Details.CODE_ID, new String(Base64Url.decode(parts[1])));
event.detail(Details.CODE_ID, new String(Base64Url.decode(parts[1])));
} catch (Throwable t) {
}
}
Map<String, String> res = new HashMap<String, String>();
res.put(OAuth2Constants.ERROR, "invalid_grant");
res.put(OAuth2Constants.ERROR_DESCRIPTION, "Code not found");
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
audit.detail(Details.CODE_ID, accessCode.getCodeId());
event.detail(Details.CODE_ID, accessCode.getCodeId());
if (!accessCode.isValid(ClientSessionModel.Action.CODE_TO_TOKEN)) {
Map<String, String> res = new HashMap<String, String>();
res.put(OAuth2Constants.ERROR, "invalid_grant");
res.put(OAuth2Constants.ERROR_DESCRIPTION, "Code is expired");
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
accessCode.setAction(null);
audit.user(accessCode.getUser());
audit.session(accessCode.getSessionState());
event.user(accessCode.getUser());
event.session(accessCode.getSessionState());
ClientModel client = authorizeClient(authorizationHeader, formData, audit);
ClientModel client = authorizeClient(authorizationHeader, formData, event);
if (!client.getClientId().equals(accessCode.getClient().getClientId())) {
Map<String, String> res = new HashMap<String, String>();
res.put(OAuth2Constants.ERROR, "invalid_grant");
res.put(OAuth2Constants.ERROR_DESCRIPTION, "Auth error");
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
@@ -777,7 +777,7 @@ public class TokenService {
Map<String, String> res = new HashMap<String, String>();
res.put(OAuth2Constants.ERROR, "invalid_grant");
res.put(OAuth2Constants.ERROR_DESCRIPTION, "User not found");
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
@@ -786,7 +786,7 @@ public class TokenService {
Map<String, String> res = new HashMap<String, String>();
res.put(OAuth2Constants.ERROR, "invalid_grant");
res.put(OAuth2Constants.ERROR_DESCRIPTION, "User disabled");
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
@@ -797,7 +797,7 @@ public class TokenService {
Map<String, String> res = new HashMap<String, String>();
res.put(OAuth2Constants.ERROR, "invalid_grant");
res.put(OAuth2Constants.ERROR_DESCRIPTION, "Session not active");
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
@@ -810,21 +810,21 @@ public class TokenService {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, e.getError());
if (e.getDescription() != null) error.put(OAuth2Constants.ERROR_DESCRIPTION, e.getDescription());
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
}
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, audit)
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event)
.accessToken(token)
.generateIDToken()
.generateRefreshToken().build();
audit.success();
event.success();
return Cors.add(request, Response.ok(res)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
}
protected ClientModel authorizeClient(String authorizationHeader, MultivaluedMap<String, String> formData, Audit audit) {
protected ClientModel authorizeClient(String authorizationHeader, MultivaluedMap<String, String> formData, EventBuilder event) {
String client_id;
String clientSecret;
if (authorizationHeader != null) {
@@ -846,14 +846,14 @@ public class TokenService {
throw new BadRequestException("Could not find client", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
}
audit.client(client_id);
event.client(client_id);
ClientModel client = realm.findClient(client_id);
if (client == null) {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, "invalid_client");
error.put(OAuth2Constants.ERROR_DESCRIPTION, "Could not find client");
audit.error(Errors.CLIENT_NOT_FOUND);
event.error(Errors.CLIENT_NOT_FOUND);
throw new BadRequestException("Could not find client", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
}
@@ -861,7 +861,7 @@ public class TokenService {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, "invalid_client");
error.put(OAuth2Constants.ERROR_DESCRIPTION, "Client is not enabled");
audit.error(Errors.CLIENT_DISABLED);
event.error(Errors.CLIENT_DISABLED);
throw new BadRequestException("Client is not enabled", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
}
@@ -869,7 +869,7 @@ public class TokenService {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, "invalid_client");
error.put(OAuth2Constants.ERROR_DESCRIPTION, "Bearer-only not allowed");
audit.error(Errors.INVALID_CLIENT);
event.error(Errors.INVALID_CLIENT);
throw new BadRequestException("Bearer-only not allowed", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
}
@@ -877,7 +877,7 @@ public class TokenService {
if (clientSecret == null || !client.validateSecret(clientSecret)) {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, "unauthorized_client");
audit.error(Errors.INVALID_CLIENT_CREDENTIALS);
event.error(Errors.INVALID_CLIENT_CREDENTIALS);
throw new BadRequestException("Unauthorized Client", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
}
}
@@ -904,7 +904,7 @@ public class TokenService {
@QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state, final @QueryParam("prompt") String prompt,
final @QueryParam("login_hint") String loginHint) {
audit.event(EventType.LOGIN).client(clientId).detail(Details.REDIRECT_URI, redirect).detail(Details.RESPONSE_TYPE, "code");
event.event(EventType.LOGIN).client(clientId).detail(Details.REDIRECT_URI, redirect).detail(Details.RESPONSE_TYPE, "code");
OAuthFlows oauth = Flows.oauth(session, realm, request, uriInfo, clientConnection, authManager, tokenManager);
@@ -913,30 +913,30 @@ public class TokenService {
}
if (!realm.isEnabled()) {
audit.error(Errors.REALM_DISABLED);
event.error(Errors.REALM_DISABLED);
return oauth.forwardToSecurityFailure("Realm not enabled");
}
ClientModel client = realm.findClient(clientId);
if (client == null) {
audit.error(Errors.CLIENT_NOT_FOUND);
event.error(Errors.CLIENT_NOT_FOUND);
return oauth.forwardToSecurityFailure("Unknown login requester.");
}
if (!client.isEnabled()) {
audit.error(Errors.CLIENT_DISABLED);
event.error(Errors.CLIENT_DISABLED);
return oauth.forwardToSecurityFailure("Login requester not enabled.");
}
if ( (client instanceof ApplicationModel) && ((ApplicationModel)client).isBearerOnly()) {
audit.error(Errors.NOT_ALLOWED);
event.error(Errors.NOT_ALLOWED);
return oauth.forwardToSecurityFailure("Bearer-only applications are not allowed to initiate browser login");
}
if (client.isDirectGrantsOnly()) {
audit.error(Errors.NOT_ALLOWED);
event.error(Errors.NOT_ALLOWED);
return oauth.forwardToSecurityFailure("direct-grants-only clients are not allowed to initiate browser login");
}
redirect = verifyRedirectUri(uriInfo, redirect, realm, client);
if (redirect == null) {
audit.error(Errors.INVALID_REDIRECT_URI);
event.error(Errors.INVALID_REDIRECT_URI);
return oauth.forwardToSecurityFailure("Invalid redirect_uri.");
}
@@ -945,8 +945,8 @@ public class TokenService {
UserModel user = authResult.getUser();
UserSessionModel session = authResult.getSession();
audit.user(user).session(session).detail(Details.AUTH_METHOD, "sso");
return oauth.processAccessCode(scopeParam, state, redirect, client, user, session, audit);
event.user(user).session(session).detail(Details.AUTH_METHOD, "sso");
return oauth.processAccessCode(scopeParam, state, redirect, client, user, session, event);
}
if (prompt != null && prompt.equals("none")) {
@@ -980,7 +980,7 @@ public class TokenService {
public Response registerPage(final @QueryParam("response_type") String responseType,
@QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) {
audit.event(EventType.REGISTER).client(clientId).detail(Details.REDIRECT_URI, redirect).detail(Details.RESPONSE_TYPE, "code");
event.event(EventType.REGISTER).client(clientId).detail(Details.REDIRECT_URI, redirect).detail(Details.RESPONSE_TYPE, "code");
OAuthFlows oauth = Flows.oauth(session, realm, request, uriInfo, clientConnection, authManager, tokenManager);
@@ -989,28 +989,28 @@ public class TokenService {
}
if (!realm.isEnabled()) {
audit.error(Errors.REALM_DISABLED);
event.error(Errors.REALM_DISABLED);
return oauth.forwardToSecurityFailure("Realm not enabled");
}
ClientModel client = realm.findClient(clientId);
if (client == null) {
audit.error(Errors.CLIENT_NOT_FOUND);
event.error(Errors.CLIENT_NOT_FOUND);
return oauth.forwardToSecurityFailure("Unknown login requester.");
}
if (!client.isEnabled()) {
audit.error(Errors.CLIENT_DISABLED);
event.error(Errors.CLIENT_DISABLED);
return oauth.forwardToSecurityFailure("Login requester not enabled.");
}
redirect = verifyRedirectUri(uriInfo, redirect, realm, client);
if (redirect == null) {
audit.error(Errors.INVALID_REDIRECT_URI);
event.error(Errors.INVALID_REDIRECT_URI);
return oauth.forwardToSecurityFailure("Invalid redirect_uri.");
}
if (!realm.isRegistrationAllowed()) {
audit.error(Errors.REGISTRATION_DISABLED);
event.error(Errors.REGISTRATION_DISABLED);
return oauth.forwardToSecurityFailure("Registration not allowed");
}
@@ -1029,9 +1029,9 @@ public class TokenService {
@GET
@NoCache
public Response logout(final @QueryParam("redirect_uri") String redirectUri) {
audit.event(EventType.LOGOUT);
event.event(EventType.LOGOUT);
if (redirectUri != null) {
audit.detail(Details.REDIRECT_URI, redirectUri);
event.detail(Details.REDIRECT_URI, redirectUri);
}
// authenticate identity cookie, but ignore an access token timeout as we're logging out anyways.
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, false);
@@ -1076,15 +1076,15 @@ public class TokenService {
throw new NotAcceptableException("HTTPS required");
}
audit.event(EventType.LOGOUT);
event.event(EventType.LOGOUT);
ClientModel client = authorizeClient(authorizationHeader, form, audit);
ClientModel client = authorizeClient(authorizationHeader, form, event);
String refreshToken = form.getFirst(OAuth2Constants.REFRESH_TOKEN);
if (refreshToken == null) {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_REQUEST);
error.put(OAuth2Constants.ERROR_DESCRIPTION, "No refresh token");
audit.error(Errors.INVALID_TOKEN);
event.error(Errors.INVALID_TOKEN);
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
}
try {
@@ -1097,7 +1097,7 @@ public class TokenService {
Map<String, String> error = new HashMap<String, String>();
error.put(OAuth2Constants.ERROR, e.getError());
if (e.getDescription() != null) error.put(OAuth2Constants.ERROR_DESCRIPTION, e.getDescription());
audit.error(Errors.INVALID_TOKEN);
event.error(Errors.INVALID_TOKEN);
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
}
return Cors.add(request, Response.noContent()).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
@@ -1105,7 +1105,7 @@ public class TokenService {
private void logout(UserSessionModel userSession) {
authManager.logout(session, realm, userSession, uriInfo, clientConnection);
audit.user(userSession.getUser()).session(userSession).success();
event.user(userSession.getUser()).session(userSession).success();
}
/**
@@ -1118,7 +1118,7 @@ public class TokenService {
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processOAuth(final MultivaluedMap<String, String> formData) {
audit.event(EventType.LOGIN).detail(Details.RESPONSE_TYPE, "code");
event.event(EventType.LOGIN).detail(Details.RESPONSE_TYPE, "code");
OAuthFlows oauth = Flows.oauth(session, realm, request, uriInfo, clientConnection, authManager, tokenManager);
@@ -1130,41 +1130,41 @@ public class TokenService {
AccessCode accessCode = AccessCode.parse(code, session, realm);
if (accessCode == null || !accessCode.isValid(ClientSessionModel.Action.OAUTH_GRANT)) {
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
return oauth.forwardToSecurityFailure("Invalid access code.");
}
audit.detail(Details.CODE_ID, accessCode.getCodeId());
event.detail(Details.CODE_ID, accessCode.getCodeId());
String redirect = accessCode.getRedirectUri();
String state = accessCode.getState();
audit.client(accessCode.getClient())
event.client(accessCode.getClient())
.user(accessCode.getUser())
.detail(Details.RESPONSE_TYPE, "code")
.detail(Details.REDIRECT_URI, redirect);
UserSessionModel userSession = session.sessions().getUserSession(realm, accessCode.getSessionState());
if (userSession != null) {
audit.detail(Details.AUTH_METHOD, userSession.getAuthMethod());
audit.detail(Details.USERNAME, userSession.getLoginUsername());
event.detail(Details.AUTH_METHOD, userSession.getAuthMethod());
event.detail(Details.USERNAME, userSession.getLoginUsername());
if (userSession.isRememberMe()) {
audit.detail(Details.REMEMBER_ME, "true");
event.detail(Details.REMEMBER_ME, "true");
}
}
if (!AuthenticationManager.isSessionValid(realm, userSession)) {
AuthenticationManager.logout(session, realm, userSession, uriInfo, clientConnection);
audit.error(Errors.INVALID_CODE);
event.error(Errors.INVALID_CODE);
return oauth.forwardToSecurityFailure("Session not active");
}
audit.session(userSession);
event.session(userSession);
if (formData.containsKey("cancel")) {
audit.error(Errors.REJECTED_BY_USER);
event.error(Errors.REJECTED_BY_USER);
return redirectAccessDenied(redirect, state);
}
audit.success();
event.success();
accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN);
return oauth.redirectAccessCode(accessCode, userSession, state, redirect);
@@ -4,10 +4,10 @@ import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.audit.AuditProvider;
import org.keycloak.audit.Event;
import org.keycloak.audit.EventQuery;
import org.keycloak.audit.EventType;
import org.keycloak.events.EventStoreProvider;
import org.keycloak.events.Event;
import org.keycloak.events.EventQuery;
import org.keycloak.events.EventType;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
@@ -19,7 +19,7 @@ import org.keycloak.models.cache.CacheUserProvider;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.adapters.action.SessionStats;
import org.keycloak.representations.idm.RealmAuditRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.LDAPConnectionTestManager;
import org.keycloak.services.managers.UsersSyncManager;
@@ -306,62 +306,62 @@ public class RealmAdminResource {
}
/**
* View the audit provider and how it is configured.
* View the events provider and how it is configured.
*
* @return
*/
@GET
@NoCache
@Path("audit")
@Path("events/config")
@Produces("application/json")
public RealmAuditRepresentation getRealmAudit() {
auth.init(RealmAuth.Resource.AUDIT).requireView();
public RealmEventsConfigRepresentation getRealmEventsConfig() {
auth.init(RealmAuth.Resource.EVENTS).requireView();
return ModelToRepresentation.toAuditReprensetation(realm);
return ModelToRepresentation.toEventsConfigReprensetation(realm);
}
/**
* Change the audit provider and/or it's configuration
* Change the events provider and/or it's configuration
*
* @param rep
*/
@PUT
@Path("audit")
@Path("events/config")
@Consumes("application/json")
public void updateRealmAudit(final RealmAuditRepresentation rep) {
auth.init(RealmAuth.Resource.AUDIT).requireManage();
public void updateRealmEventsConfig(final RealmEventsConfigRepresentation rep) {
auth.init(RealmAuth.Resource.EVENTS).requireManage();
logger.debug("updating realm audit: " + realm.getName());
new RealmManager(session).updateRealmAudit(rep, realm);
logger.debug("updating realm events config: " + realm.getName());
new RealmManager(session).updateRealmEventsConfig(rep, realm);
}
/**
* Query audit events. Returns all events, or will query based on URL query parameters listed here
* Query events. Returns all events, or will query based on URL query parameters listed here
*
* @param client app or oauth client name
* @param event event type
* @param type type type
* @param user user id
* @param ipAddress
* @param firstResult
* @param maxResults
* @return
*/
@Path("audit/events")
@Path("events")
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public List<Event> getAudit(@QueryParam("client") String client, @QueryParam("event") String event, @QueryParam("user") String user,
@QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) {
auth.init(RealmAuth.Resource.AUDIT).requireView();
public List<Event> getEvents(@QueryParam("client") String client, @QueryParam("type") String type, @QueryParam("user") String user,
@QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) {
auth.init(RealmAuth.Resource.EVENTS).requireView();
AuditProvider audit = session.getProvider(AuditProvider.class);
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
EventQuery query = audit.createQuery().realm(realm.getId());
EventQuery query = eventStore.createQuery().realm(realm.getId());
if (client != null) {
query.client(client);
}
if (event != null) {
query.event(EventType.valueOf(event));
if (type != null) {
query.type(EventType.valueOf(type));
}
if (user != null) {
query.user(user);
@@ -380,16 +380,16 @@ public class RealmAdminResource {
}
/**
* Delete all audit events.
* Delete all events.
*
*/
@Path("audit/events")
@Path("events")
@DELETE
public void clearAudit() {
auth.init(RealmAuth.Resource.AUDIT).requireManage();
public void clearEvents() {
auth.init(RealmAuth.Resource.EVENTS).requireManage();
AuditProvider audit = session.getProvider(AuditProvider.class);
audit.clear(realm.getId());
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
eventStore.clear(realm.getId());
}
@Path("testLDAPConnection")
@@ -13,7 +13,7 @@ public class RealmAuth {
private Resource resource;
public enum Resource {
APPLICATION, CLIENT, USER, REALM, AUDIT
APPLICATION, CLIENT, USER, REALM, EVENTS
}
private AdminAuth auth;
@@ -65,8 +65,8 @@ public class RealmAuth {
return AdminRoles.VIEW_USERS;
case REALM:
return AdminRoles.VIEW_REALM;
case AUDIT:
return AdminRoles.VIEW_AUDIT;
case EVENTS:
return AdminRoles.VIEW_EVENTS;
default:
throw new IllegalStateException();
}
@@ -82,8 +82,8 @@ public class RealmAuth {
return AdminRoles.MANAGE_USERS;
case REALM:
return AdminRoles.MANAGE_REALM;
case AUDIT:
return AdminRoles.MANAGE_AUDIT;
case EVENTS:
return AdminRoles.MANAGE_EVENTS;
default:
throw new IllegalStateException();
}
@@ -1,7 +1,7 @@
package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.audit.AuditListener;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.freemarker.Theme;
import org.keycloak.freemarker.ThemeProvider;
import org.keycloak.models.KeycloakSession;
@@ -26,7 +26,7 @@ public class ServerInfoAdminResource {
private KeycloakSession session;
/**
* Returns a list of themes, social providers, auth providers, and audit listeners available on this server
* Returns a list of themes, social providers, auth providers, and event listeners available on this server
*
* @return
*/
@@ -36,7 +36,7 @@ public class ServerInfoAdminResource {
ServerInfoRepresentation info = new ServerInfoRepresentation();
setSocialProviders(info);
setThemes(info);
setAuditListeners(info);
setEventListeners(info);
return info;
}
@@ -60,12 +60,12 @@ public class ServerInfoAdminResource {
Collections.sort(info.socialProviders);
}
private void setAuditListeners(ServerInfoRepresentation info) {
info.auditListeners = new LinkedList<String>();
private void setEventListeners(ServerInfoRepresentation info) {
info.eventListeners = new LinkedList<String>();
Set<String> providers = session.listProviderIds(AuditListener.class);
Set<String> providers = session.listProviderIds(EventListenerProvider.class);
if (providers != null) {
info.auditListeners.addAll(providers);
info.eventListeners.addAll(providers);
}
}
@@ -76,7 +76,7 @@ public class ServerInfoAdminResource {
private List<String> socialProviders;
private List<String> auditListeners;
private List<String> eventListeners;
public ServerInfoRepresentation() {
}
@@ -89,8 +89,8 @@ public class ServerInfoAdminResource {
return socialProviders;
}
public List<String> getAuditListeners() {
return auditListeners;
public List<String> getEventListeners() {
return eventListeners;
}
}
@@ -5,7 +5,6 @@ import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.ClientConnection;
import org.keycloak.audit.Details;
import org.keycloak.email.EmailException;
import org.keycloak.email.EmailProvider;
import org.keycloak.models.ApplicationModel;
@@ -26,9 +26,9 @@ import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
import org.keycloak.OAuth2Constants;
import org.keycloak.audit.Audit;
import org.keycloak.audit.Details;
import org.keycloak.audit.EventType;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.Details;
import org.keycloak.events.EventType;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
@@ -124,7 +124,7 @@ public class OAuthFlows {
return Response.status(302).location(redirectUri.build()).build();
}
public Response processAccessCode(String scopeParam, String state, String redirect, ClientModel client, UserModel user, UserSessionModel session, Audit audit) {
public Response processAccessCode(String scopeParam, String state, String redirect, ClientModel client, UserModel user, UserSessionModel session, EventBuilder event) {
isTotpConfigurationRequired(user);
isEmailVerificationRequired(user);
@@ -135,7 +135,7 @@ public class OAuthFlows {
log.debugv("processAccessCode: go to oauth page?: {0}",
!isResource);
audit.detail(Details.CODE_ID, accessCode.getCodeId());
event.detail(Details.CODE_ID, accessCode.getCodeId());
Set<RequiredAction> requiredActions = user.getRequiredActions();
if (!requiredActions.isEmpty()) {
@@ -143,7 +143,7 @@ public class OAuthFlows {
accessCode.setRequiredAction(action);
if (action.equals(RequiredAction.VERIFY_EMAIL)) {
audit.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, accessCode.getUser().getEmail()).success();
event.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, accessCode.getUser().getEmail()).success();
}
return Flows.forms(this.session, realm, client, uriInfo).setAccessCode(accessCode.getCode()).setUser(user)
@@ -171,7 +171,7 @@ public class OAuthFlows {
}
if (redirect != null) {
audit.success();
event.success();
accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN);
return redirectAccessCode(accessCode, session, state, redirect);
@@ -1,22 +1,22 @@
package org.keycloak.services.scheduled;
import org.keycloak.audit.AuditProvider;
import org.keycloak.events.EventStoreProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ClearExpiredAuditEvents implements ScheduledTask {
public class ClearExpiredEvents implements ScheduledTask {
@Override
public void run(KeycloakSession session) {
AuditProvider audit = session.getProvider(AuditProvider.class);
if (audit != null) {
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
if (eventStore != null) {
for (RealmModel realm : session.realms().getRealms()) {
if (realm.isAuditEnabled() && realm.getAuditExpiration() > 0) {
long olderThan = System.currentTimeMillis() - realm.getAuditExpiration() * 1000;
audit.clear(realm.getId(), olderThan);
if (realm.isEventsEnabled() && realm.getEventsExpiration() > 0) {
long olderThan = System.currentTimeMillis() - realm.getEventsExpiration() * 1000;
eventStore.clear(realm.getId(), olderThan);
}
}
}