Skip to content

Fix OAuth2 Client with Ditributed Session #6215

Closed
@wangzw

Description

@wangzw

I got the following error message and after the whole day debug, I found that oauth2 client failed to save AuthorizationRequest to session in some case.

Resolved [OAuth2AuthorizationException: [authorization_request_not_found] ]

To trigger the issue, you have to:

  1. With reactor server
  2. Configure redis session. (or hazelcast session)
  3. Some errors happened before and one or more legacy AuthorizationRequest leaved in the session

Result:
Oauth2 client will continue failing with error authorization_request_not_found

Root cause:

in ReactiveRedisOperationsSessionRepository.java

	@Override
	public Mono<Void> save(RedisSession session) {
		Mono<Void> result = session.saveChangeSessionId().and(session.saveDelta())
				.and((s) -> {
					session.isNew = false;
					s.onComplete();
				});
		if (session.isNew) {
			return result;
		}
		else {
			String sessionKey = getSessionKey(
					session.hasChangedSessionId() ? session.originalSessionId
							: session.getId());
			return this.sessionRedisOperations.hasKey(sessionKey)
					.flatMap((exists) -> exists ? result
							: Mono.error(new IllegalStateException(
									"Session was invalidated")));
		}
	}

Only the delta data session.saveDelta() will be update in redis session.

And the delta is captured by WebSession::getAttributes::setAttribute

	@Override
	public void setAttribute(String attributeName, Object attributeValue) {
		this.cached.setAttribute(attributeName, attributeValue);
		putAndFlush(getAttributeKey(attributeName), attributeValue);
	}

	private void putAndFlush(String a, Object v) {
		this.delta.put(a, v);
		flushImmediateIfNecessary();
	}

But In WebSessionOAuth2ServerAuthorizationRequestRepository.java

It get state to AuthorizationRequest map from session's attribute and update its value, And does not put the map back to session's attribute again by calling setAttribute. So redis session will not capture such change and fail to update the modification.

	@Override
	public Mono<Void> saveAuthorizationRequest(
			OAuth2AuthorizationRequest authorizationRequest, ServerWebExchange exchange) {
		Assert.notNull(authorizationRequest, "authorizationRequest cannot be null");
		return getStateToAuthorizationRequest(exchange, true)
				.doOnNext(stateToAuthorizationRequest -> stateToAuthorizationRequest.put(authorizationRequest.getState(), authorizationRequest))
				.then();
	}

	private Mono<Map<String, OAuth2AuthorizationRequest>> getStateToAuthorizationRequest(ServerWebExchange exchange, boolean create) {
		Assert.notNull(exchange, "exchange cannot be null");

		return getSessionAttributes(exchange)
			.doOnNext(sessionAttrs -> {
				if (create) {
					sessionAttrs.putIfAbsent(this.sessionAttributeName, new HashMap<String, OAuth2AuthorizationRequest>());
				}
			})
			.flatMap(sessionAttrs -> Mono.justOrEmpty(this.sessionAttrsMapStateToAuthorizationRequest(sessionAttrs)));
	}

	private Map<String, OAuth2AuthorizationRequest> sessionAttrsMapStateToAuthorizationRequest(Map<String, Object> sessionAttrs) {
		return (Map<String, OAuth2AuthorizationRequest>) sessionAttrs.get(this.sessionAttributeName);
	}

And then authorization_request_not_found will be raised since AuthorizationRequest is not in session.

Metadata

Metadata

Assignees

Labels

in: oauth2An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions