001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.server.auth.oidc.rp; 018 019import java.util.*; 020 021/** 022 * SPI for persisting {@link OidcSession} instances and resolving them back from a session-cookie value. 023 * 024 * <p> 025 * Two implementations are bundled: 026 * <ul> 027 * <li>{@link SignedCookieSessionStore} — the documented default. Stateless: the session is 028 * HMAC-signed and stored entirely in the cookie value. Scales horizontally and survives restarts 029 * with no shared store, but <b>cannot be server-revoked</b> (so it does not support back-channel 030 * logout — see {@link #supportsServerSideRevocation()}). 031 * <li>{@link InMemorySessionStore} — the simpler single-instance / dev option. Server-side 032 * indexed by {@code sub} and {@code sid}, so it <b>does</b> support back-channel logout. Lost on 033 * restart; breaks under horizontal scaling without sticky sessions. 034 * </ul> 035 * 036 * <p> 037 * Distributed stores (Redis / JDBC) are caller-supplied via this SPI. A distributed store that wants 038 * to participate in back-channel logout must implement {@link #invalidateBySubject(String)} / 039 * {@link #invalidateBySessionId(String)} and report {@link #supportsServerSideRevocation()} as 040 * <jk>true</jk>. 041 * 042 * <p> 043 * Implementations must be thread-safe. 044 * 045 * <h5 class='section'>See Also:</h5><ul> 046 * <li class='jc'>{@link OidcSession} 047 * <li class='jc'>{@link InMemorySessionStore} 048 * <li class='jc'>{@link SignedCookieSessionStore} 049 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/OidcRelyingParty">OIDC Relying Party Login (juneau-rest-server-auth-oidc-rp)</a> 050 * </ul> 051 * 052 * @since 10.0.0 053 */ 054public interface SessionStore { 055 056 /** 057 * Persists the supplied session and returns the opaque value to set as the session cookie. 058 * 059 * <p> 060 * For a server-side store this is typically a random session id used as a lookup key; for a 061 * stateless cookie store it is the entire signed session payload. 062 * 063 * @param session The session to persist. Must not be <jk>null</jk>. 064 * @return The cookie value the client should send back on subsequent requests. Never <jk>null</jk>. 065 */ 066 String createSessionCookieValue(OidcSession session); 067 068 /** 069 * Resolves a session from a cookie value. 070 * 071 * @param cookieValue The cookie value previously returned by {@link #createSessionCookieValue}. 072 * Must not be <jk>null</jk>. 073 * @return The resolved session, or {@link Optional#empty()} if absent, expired, invalid, or 074 * tampered. 075 */ 076 Optional<OidcSession> lookup(String cookieValue); 077 078 /** 079 * Invalidates the session identified by the supplied cookie value. No-op if absent. 080 * 081 * @param cookieValue The cookie value. Must not be <jk>null</jk>. 082 */ 083 void invalidate(String cookieValue); 084 085 /** 086 * Returns whether this store can revoke sessions server-side (a prerequisite for back-channel 087 * logout). 088 * 089 * <p> 090 * Defaults to <jk>false</jk> — stateless cookie stores cannot revoke a session the server 091 * never retained. 092 * 093 * @return <jk>true</jk> if {@link #invalidateBySubject(String)} / {@link #invalidateBySessionId(String)} 094 * are supported. 095 */ 096 default boolean supportsServerSideRevocation() { 097 return false; 098 } 099 100 /** 101 * Invalidates every session belonging to the supplied subject ({@code sub}). 102 * 103 * <p> 104 * Used by {@link OidcRelyingParty#backChannelLogout} when the IdP-pushed logout token carries a 105 * {@code sub} but no {@code sid}. 106 * 107 * @param subject The subject identifier. Must not be <jk>null</jk> or blank. 108 * @return The number of sessions invalidated. 109 * @throws UnsupportedOperationException If this store does not support server-side revocation. 110 */ 111 default int invalidateBySubject(String subject) { 112 throw new UnsupportedOperationException("This SessionStore does not support server-side revocation (back-channel logout requires an in-memory or distributed store)."); 113 } 114 115 /** 116 * Invalidates the session(s) bound to the supplied IdP session id ({@code sid}). 117 * 118 * <p> 119 * Used by {@link OidcRelyingParty#backChannelLogout} when the IdP-pushed logout token carries a 120 * {@code sid}. 121 * 122 * @param sid The IdP session id. Must not be <jk>null</jk> or blank. 123 * @return The number of sessions invalidated. 124 * @throws UnsupportedOperationException If this store does not support server-side revocation. 125 */ 126 default int invalidateBySessionId(String sid) { 127 throw new UnsupportedOperationException("This SessionStore does not support server-side revocation (back-channel logout requires an in-memory or distributed store)."); 128 } 129}