diff --git a/inception/inception-log/pom.xml b/inception/inception-log/pom.xml index cbdbe468c83..360911778b5 100644 --- a/inception/inception-log/pom.xml +++ b/inception/inception-log/pom.xml @@ -94,6 +94,10 @@ org.springframework.security spring-security-core + + org.springframework.security + spring-security-web + org.slf4j @@ -131,6 +135,11 @@ javax.persistence javax.persistence-api + + javax.servlet + javax.servlet-api + provided + @@ -179,4 +188,21 @@ test + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + javax.servlet:javax.servlet-api + + + + + + diff --git a/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/AuthenticationSuccessEventAdapter.java b/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/AuthenticationSuccessEventAdapter.java new file mode 100644 index 00000000000..81a64e44c97 --- /dev/null +++ b/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/AuthenticationSuccessEventAdapter.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Technische Universität Darmstadt under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The Technische Universität Darmstadt + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.tudarmstadt.ukp.inception.log.adapter; + +import java.io.IOException; + +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; + +import de.tudarmstadt.ukp.clarin.webanno.support.JSONUtil; +import de.tudarmstadt.ukp.inception.log.model.SessionDetails; + +@Component +public class AuthenticationSuccessEventAdapter + implements EventLoggingAdapter +{ + @Override + public boolean accepts(Object aEvent) + { + return aEvent instanceof AuthenticationSuccessEvent; + } + + @Override + public String getEvent(AuthenticationSuccessEvent aEvent) + { + return "UserSessionStartedEvent"; + } + + @Override + public String getUser(AuthenticationSuccessEvent aEvent) + { + return aEvent.getAuthentication().getName(); + } + + @Override + public String getDetails(AuthenticationSuccessEvent aEvent) throws IOException + { + String sessionId; + + try { + sessionId = RequestContextHolder.currentRequestAttributes().getSessionId(); + + SessionDetails details = new SessionDetails(sessionId); + + return JSONUtil.toJsonString(details); + } + catch (Exception e) { + // Ignore + } + + return null; + } +} diff --git a/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/EventLoggingAdapter.java b/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/EventLoggingAdapter.java index eca9806546d..c9dbf633af3 100644 --- a/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/EventLoggingAdapter.java +++ b/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/EventLoggingAdapter.java @@ -27,6 +27,9 @@ public interface EventLoggingAdapter { + public static final String SYSTEM_USER = ""; + public static final String ANONYMOUS_USER = "anonymousUser"; + boolean accepts(Object aEvent); default String getDetails(T aEvent) throws Exception @@ -71,7 +74,7 @@ default String getUser(T aEvent) return context.getAuthentication().getName(); } else { - return ""; + return SYSTEM_USER; } } diff --git a/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/HttpSessionDestroyedEventAdapter.java b/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/HttpSessionDestroyedEventAdapter.java new file mode 100644 index 00000000000..05fc0dc7157 --- /dev/null +++ b/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/adapter/HttpSessionDestroyedEventAdapter.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Technische Universität Darmstadt under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The Technische Universität Darmstadt + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.tudarmstadt.ukp.inception.log.adapter; + +import java.io.IOException; +import java.util.Set; + +import org.springframework.security.web.session.HttpSessionDestroyedEvent; +import org.springframework.stereotype.Component; + +import de.tudarmstadt.ukp.clarin.webanno.support.JSONUtil; +import de.tudarmstadt.ukp.inception.log.model.SessionDetails; + +@Component +public class HttpSessionDestroyedEventAdapter + implements EventLoggingAdapter +{ + private static final Set IGNORE_USERS = Set.of(ANONYMOUS_USER, SYSTEM_USER); + + @Override + public boolean accepts(Object aEvent) + { + if (!(aEvent instanceof HttpSessionDestroyedEvent)) { + return false; + } + + var user = getUser((HttpSessionDestroyedEvent) aEvent); + if (IGNORE_USERS.contains(user)) { + return false; + } + + return true; + } + + @Override + public String getEvent(HttpSessionDestroyedEvent aEvent) + { + return "UserSessionEndedEvent"; + } + + @Override + public String getUser(HttpSessionDestroyedEvent aEvent) + { + if (aEvent.getSecurityContexts().isEmpty()) { + return EventLoggingAdapter.super.getUser(aEvent); + } + + return aEvent.getSecurityContexts().get(0).getAuthentication().getName(); + } + + @Override + public String getDetails(HttpSessionDestroyedEvent aEvent) throws IOException + { + var age = (System.currentTimeMillis() - aEvent.getSession().getLastAccessedTime()) / 1000; + + var details = new SessionDetails(aEvent.getId()); + details.setDuration( + aEvent.getSession().getLastAccessedTime() - aEvent.getSession().getCreationTime()); + if (age > aEvent.getSession().getMaxInactiveInterval()) { + details.setExpiredAfterInactivity(age * 1000); + } + + return JSONUtil.toJsonString(details); + } +} diff --git a/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/model/SessionDetails.java b/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/model/SessionDetails.java new file mode 100644 index 00000000000..042134e4d7c --- /dev/null +++ b/inception/inception-log/src/main/java/de/tudarmstadt/ukp/inception/log/model/SessionDetails.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Technische Universität Darmstadt under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The Technische Universität Darmstadt + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.tudarmstadt.ukp.inception.log.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +@JsonInclude(Include.NON_NULL) +public class SessionDetails +{ + private String sessionId; + + @JsonInclude(Include.NON_DEFAULT) + private long expiredAfterInactivity; + + @JsonInclude(Include.NON_DEFAULT) + private long duration; + + public SessionDetails() + { + // Nothing to do + } + + public SessionDetails(String aId) + { + sessionId = aId; + } + + public String getSessionId() + { + return sessionId; + } + + public void setSessionId(String aSessionId) + { + sessionId = aSessionId; + } + + /** + * @return expired after milliseconds of inactivity + */ + public long getExpiredAfterInactivity() + { + return expiredAfterInactivity; + } + + public void setExpiredAfterInactivity(long aExpiredAfterInactivity) + { + expiredAfterInactivity = aExpiredAfterInactivity; + } + + /** + * @return duration of the session in milliseconds. + */ + public long getDuration() + { + return duration; + } + + public void setDuration(long aDuration) + { + duration = aDuration; + } +}