Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package org.eclipse.scout.rt.platform.security;

import java.security.Principal;
import java.util.Objects;

import org.ietf.jgss.GSSCredential;

Expand All @@ -34,4 +35,17 @@ public String getName() {
public GSSCredential getDelegatedCred() {
return m_delegatedCred;
}

@Override
public boolean equals(Object o) {
if (!(o instanceof SimplePrincipalWithDelegation that)) {
return false;
}
return Objects.equals(m_name, that.m_name) && Objects.equals(m_delegatedCred, that.m_delegatedCred);
}

@Override
public int hashCode() {
return Objects.hash(m_name, m_delegatedCred);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2023 BSI Business Systems Integration AG
* Copyright (c) 2010, 2026 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -38,13 +38,7 @@
*/
@Bean
public interface IAccessController {

/**
* Allows to inform the {@link org.eclipse.scout.rt.ui.html.IUiSession} that a new Subject is created by an
* {@link IAccessController} that should be updated on the {@link org.eclipse.scout.rt.client.IClientSession}
*/
String UPDATED_SUBJECT = "scout.authentication.updatedSubject";


/**
* Invoke to authenticate the given {@link HttpServletRequest}.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import java.util.List;
import java.util.stream.Collectors;

import javax.security.auth.Subject;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
Expand All @@ -36,7 +38,9 @@
import org.eclipse.scout.rt.platform.IBeanInstanceProducer;
import org.eclipse.scout.rt.platform.IgnoreBean;
import org.eclipse.scout.rt.platform.classid.ClassId;
import org.eclipse.scout.rt.platform.context.RunContext;
import org.eclipse.scout.rt.platform.job.Jobs;
import org.eclipse.scout.rt.platform.util.ObjectUtility;
import org.eclipse.scout.rt.server.commons.BufferedServletOutputStream;
import org.eclipse.scout.rt.testing.platform.BeanTestingHelper;
import org.eclipse.scout.rt.testing.platform.job.JobTestUtil;
Expand All @@ -50,6 +54,7 @@
import org.eclipse.scout.rt.ui.html.json.testing.TestEnvironmentUiSession;
import org.json.JSONObject;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -134,7 +139,8 @@ public void testStartupThenModelStop() throws IOException {
"UiSession.getOrCreateClientSession",
"ClientSession.execLoadSession",
"Desktop.execOpened",
"Desktop.execGuiAttached"),
"Desktop.execGuiAttached",
"UiSession.verifySubject"),
m_protocol);
m_protocol.clear();

Expand Down Expand Up @@ -190,11 +196,12 @@ public void testStartupThenBrowserTabClose() throws IOException {
"UiSession.getOrCreateClientSession",
"ClientSession.execLoadSession",
"Desktop.execOpened",
"Desktop.execGuiAttached"),
"Desktop.execGuiAttached",
"UiSession.verifySubject"),
m_protocol);
m_protocol.clear();

//brower tab closed -> json unload
//browser tab closed -> json unload
try (BufferedServletOutputStream out = new BufferedServletOutputStream()) {
final HttpServletRequest req = JsonTestUtility.createHttpServletRequest(httpSession, "/unload/" + uiSessionId, null);
final HttpServletResponse resp = JsonTestUtility.createHttpServletResponse(out);
Expand Down Expand Up @@ -248,11 +255,12 @@ public void testStartupThenBrowserTabReload() throws IOException {
"UiSession.getOrCreateClientSession",
"ClientSession.execLoadSession",
"Desktop.execOpened",
"Desktop.execGuiAttached"),
"Desktop.execGuiAttached",
"UiSession.verifySubject"),
m_protocol);
m_protocol.clear();

//brower tab reload -> json unload
//browser tab reload -> json unload
try (BufferedServletOutputStream out = new BufferedServletOutputStream()) {
final HttpServletRequest req = JsonTestUtility.createHttpServletRequest(httpSession, "/unload/" + uiSessionId, null);
final HttpServletResponse resp = JsonTestUtility.createHttpServletResponse(out);
Expand Down Expand Up @@ -288,13 +296,14 @@ public void testStartupThenBrowserTabReload() throws IOException {
Arrays.asList(
"UiSession.dispose",
"UiSession.init",
"UiSession.getOrCreateClientSession"),
"UiSession.getOrCreateClientSession",
"UiSession.verifySubject"),
m_protocol.stream().filter(s -> s.startsWith("UiSession.")).collect(Collectors.toList()));
m_protocol.clear();
assertEquals(1, store.countClientSessions());
assertEquals(1, store.countUiSessions());

//brower tab closed -> json unload
//browser tab closed -> json unload
try (BufferedServletOutputStream out = new BufferedServletOutputStream()) {
final HttpServletRequest req = JsonTestUtility.createHttpServletRequest(httpSession, "/unload/" + uiSessionId, null);
final HttpServletResponse resp = JsonTestUtility.createHttpServletResponse(out);
Expand Down Expand Up @@ -345,11 +354,12 @@ public void testStartupThenBrowserTabDuplicate() throws IOException {
"UiSession.getOrCreateClientSession",
"ClientSession.execLoadSession",
"Desktop.execOpened",
"Desktop.execGuiAttached"),
"Desktop.execGuiAttached",
"UiSession.verifySubject"),
m_protocol);
m_protocol.clear();

//brower tab duplicate -> json startup with same client session
//browser tab duplicate -> json startup with same client session
// this results in two UiSessions attached to the same client session
final String clientSessionIdB;
final String uiSessionIdB;
Expand All @@ -367,8 +377,9 @@ public void testStartupThenBrowserTabDuplicate() throws IOException {
assertEquals(
Arrays.asList(
"UiSession.init",
"UiSession.getOrCreateClientSession"
"UiSession.getOrCreateClientSession",
// "Desktop.execGuiAttached" -> this is not called because there is already uiSessionA attached to the clientSession
"UiSession.verifySubject"
),
m_protocol);
m_protocol.clear();
Expand All @@ -379,13 +390,13 @@ public void testStartupThenBrowserTabDuplicate() throws IOException {

final FixtureClientSession clientSession = (FixtureClientSession) store.getClientSessionMap().values().iterator().next();

//brower tab A closed -> json unload
//browser tab A closed -> json unload
try (BufferedServletOutputStream out = new BufferedServletOutputStream()) {
final HttpServletRequest req = JsonTestUtility.createHttpServletRequest(httpSession, "/unload/" + uiSessionIdA, null);
final HttpServletResponse resp = JsonTestUtility.createHttpServletResponse(out);
unloadHandler.handlePost(req, resp);
}
//brower tab B closed -> json unload
//browser tab B closed -> json unload
try (BufferedServletOutputStream out = new BufferedServletOutputStream()) {
final HttpServletRequest req = JsonTestUtility.createHttpServletRequest(httpSession, "/unload/" + uiSessionIdB, null);
final HttpServletResponse resp = JsonTestUtility.createHttpServletResponse(out);
Expand Down Expand Up @@ -450,11 +461,12 @@ public void testStartupThenBrowserTabDuplicateThenBrowserTabClose() throws IOExc
"UiSession.getOrCreateClientSession",
"ClientSession.execLoadSession",
"Desktop.execOpened",
"Desktop.execGuiAttached"),
"Desktop.execGuiAttached",
"UiSession.verifySubject"),
m_protocol);
m_protocol.clear();

//brower tab duplicate -> json startup with same client session
//browser tab duplicate -> json startup with same client session
// this results in two UiSessions attached to the same client session
final String clientSessionIdB;
final String uiSessionIdB;
Expand All @@ -472,8 +484,9 @@ public void testStartupThenBrowserTabDuplicateThenBrowserTabClose() throws IOExc
assertEquals(
Arrays.asList(
"UiSession.init",
"UiSession.getOrCreateClientSession"
"UiSession.getOrCreateClientSession",
// "Desktop.execGuiAttached" -> this is not called because there is already uiSessionA attached to the clientSession
"UiSession.verifySubject"
),
m_protocol);
m_protocol.clear();
Expand All @@ -482,7 +495,7 @@ public void testStartupThenBrowserTabDuplicateThenBrowserTabClose() throws IOExc
assertNotEquals(uiSessionIdA, uiSessionIdB);
assertEquals(2, store.countUiSessions());

//brower tab A closed -> json unload
//browser tab A closed -> json unload
final IClientSession clientSessionA = store.getClientSessionMap().get(clientSessionIdA);
try (BufferedServletOutputStream out = new BufferedServletOutputStream()) {
final HttpServletRequest req = JsonTestUtility.createHttpServletRequest(httpSession, "/unload/" + uiSessionIdA, null);
Expand All @@ -508,7 +521,7 @@ public void testStartupThenBrowserTabDuplicateThenBrowserTabClose() throws IOExc
assertEquals(1, store.countClientSessions());
assertEquals(1, store.countUiSessions());

//brower tab B closed -> json unload
//browser tab B closed -> json unload
try (BufferedServletOutputStream out = new BufferedServletOutputStream()) {
final HttpServletRequest req = JsonTestUtility.createHttpServletRequest(httpSession, "/unload/" + uiSessionIdB, null);
final HttpServletResponse resp = JsonTestUtility.createHttpServletResponse(out);
Expand Down Expand Up @@ -563,6 +576,22 @@ public void dispose() {
writeToProtocol("UiSession.dispose");
super.dispose();
}

@Override
public void verifySubject(HttpServletRequest request) {
writeToProtocol("UiSession.verifySubject");

if (getClientSession() == null) {
return;
}
Subject subject = RunContext.CURRENT.get().getSubject();
if (subject == null) {
return;
}
if (!ObjectUtility.equals(subject, getClientSession().getSubject())) {
Assert.fail("Subject didn't change and shouldn't be updated");
}
}
}

@IgnoreBean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.security.auth.Subject;

import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionBindingListener;

Expand All @@ -31,6 +33,10 @@
import org.eclipse.scout.rt.platform.context.RunContexts;
import org.eclipse.scout.rt.platform.job.IFuture;
import org.eclipse.scout.rt.platform.job.Jobs;
import org.eclipse.scout.rt.platform.security.JwtPrincipal;
import org.eclipse.scout.rt.platform.security.SamlPrincipal;
import org.eclipse.scout.rt.platform.security.SimplePrincipal;
import org.eclipse.scout.rt.platform.security.SimplePrincipalWithDelegation;
import org.eclipse.scout.rt.testing.platform.BeanTestingHelper;
import org.eclipse.scout.rt.testing.platform.job.JobTestUtil;
import org.eclipse.scout.rt.testing.platform.runner.JUnitExceptionHandler;
Expand Down Expand Up @@ -107,6 +113,30 @@ public void testLogout() {
JsonTestUtility.endRequest(uiSession);
}

@Test
public void testVerifySubject() {
UiSession uiSession = (UiSession) JsonTestUtility.createAndInitializeUiSession();

// Update Subject
Subject subject = new Subject();
subject.getPrincipals().add(new SimplePrincipal("NewPrinciple0"));
subject.getPrincipals().add(new JwtPrincipal("NewPrinciple1", "testTokenString"));
subject.getPrincipals().add(new SamlPrincipal("NewPrinciple2", null));
subject.getPrincipals().add(new SimplePrincipalWithDelegation("NewPrinciple3", null));
subject.setReadOnly();

Subject oldSubject = uiSession.getClientSession().getSubject();

RunContext.CURRENT.get()
.withSubject(subject);

uiSession.verifySubject(null);

assertEquals(subject, uiSession.getClientSession().getSubject());
assertNotEquals(oldSubject, subject);
JsonTestUtility.endRequest(uiSession);
}

@Test
public void testSessionInvalidation() {
UiSession uiSession = (UiSession) JsonTestUtility.createAndInitializeUiSession();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
import org.eclipse.scout.rt.platform.util.concurrent.FutureCancelledError;
import org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError;
import org.eclipse.scout.rt.platform.util.concurrent.TimedOutError;
import org.eclipse.scout.rt.server.commons.authentication.IAccessController;
import org.eclipse.scout.rt.server.commons.servlet.CookieUtility;
import org.eclipse.scout.rt.server.commons.servlet.HttpClientInfo;
import org.eclipse.scout.rt.server.commons.servlet.UrlHints;
Expand Down Expand Up @@ -812,8 +811,7 @@ public JSONObject getAlreadyProcessedResponse(JsonRequest jsonRequest) {

/**
* Verifies if an access controller has created a new {@link Subject} and replaces the current one on the
* {@link IClientSession} with the new one. An {@link IAccessController} can request this by setting the
* {@link IAccessController#UPDATED_SUBJECT} attribute on the request.
* {@link IClientSession} with the new one.
*/
@Override
public void verifySubject(HttpServletRequest request) {
Expand All @@ -824,7 +822,7 @@ public void verifySubject(HttpServletRequest request) {
if (subject == null) {
return;
}
if (request.getAttribute(IAccessController.UPDATED_SUBJECT) != null) {
if (!ObjectUtility.equals(subject, m_clientSession.getSubject())) {
m_clientSession.setSubject(subject);
}
}
Expand Down
Loading