package org.apereo.cas.support.oauth.validator.token;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.support.oauth.OAuth20Constants;
import org.apereo.cas.support.oauth.OAuth20GrantTypes;
import org.apereo.cas.support.oauth.services.OAuthRegisteredService;
import org.apereo.cas.support.oauth.util.OAuth20Utils;
import org.apereo.cas.support.oauth.validator.OAuth20Validator;
import org.apereo.cas.ticket.OAuthToken;
import org.apereo.cas.ticket.code.OAuthCode;
import org.apereo.cas.ticket.registry.TicketRegistry;
import org.pac4j.core.context.J2EContext;
import org.pac4j.core.profile.ProfileManager;
import org.pac4j.core.profile.UserProfile;

import javax.servlet.http.HttpServletRequest;

/**
 * This is {@link OAuth20AuthorizationCodeGrantTypeTokenRequestValidator}.
 *
 * @author Misagh Moayyed
 * @since 5.3.0
 */
@Slf4j
@RequiredArgsConstructor
public class OAuth20AuthorizationCodeGrantTypeTokenRequestValidator extends BaseOAuth20TokenRequestValidator {
    private final ServicesManager servicesManager;
    private final TicketRegistry ticketRegistry;
    private final OAuth20Validator validator;

    @Override
    protected OAuth20GrantTypes getGrantType() {
        return OAuth20GrantTypes.AUTHORIZATION_CODE;
    }

    @Override
    protected boolean validateInternal(final J2EContext context, final String grantType,
                                       final ProfileManager manager, final UserProfile uProfile) {
        final HttpServletRequest request = context.getRequest();
        final String clientId = uProfile.getId();
        final String redirectUri = request.getParameter(OAuth20Constants.REDIRECT_URI);
        final OAuthRegisteredService registeredService = OAuth20Utils.getRegisteredOAuthServiceByClientId(this.servicesManager, clientId);

        LOGGER.debug("Received grant type [{}] with client id [{}] and redirect URI [{}]", grantType, clientId, redirectUri);
        final boolean valid = this.validator.checkParameterExist(request, OAuth20Constants.REDIRECT_URI)
            && this.validator.checkParameterExist(request, OAuth20Constants.CODE)
            && this.validator.checkCallbackValid(registeredService, redirectUri);

        if (valid) {
            final String code = context.getRequestParameter(OAuth20Constants.CODE);
            final OAuthToken token = ticketRegistry.getTicket(code, OAuthCode.class);
            if (token == null || token.isExpired()) {
                LOGGER.warn("Request OAuth code [{}] is not found or has expired", code);
                return false;
            }
            if (!registeredService.matches(token.getService())) {
                LOGGER.warn("The OAuth code [{}] issued to service [{}] does not match the registered service [{}] provided in the request given the redirect URI [{}]",
                    code, token.getService().getId(), registeredService.getName(), redirectUri);
                return false;
            }
            return true;
        }
        LOGGER.warn("Access token request cannot be validated for grant type [{}} and client id [{}] given the redirect URI [{}]", grantType, clientId, redirectUri);
        return false;
    }
}

@@ -1768,17 +1768,23 @@
 Service 
-r
+clientR
 egistere
@@ -2112,32 +2112,36 @@
 RI)%0A            
+    
 && this.validato
@@ -2198,32 +2198,36 @@
 DE)%0A            
+    
 && this.validato
@@ -2247,17 +2247,23 @@
 ckValid(
-r
+clientR
 egistere
@@ -2682,57 +2682,298 @@
     
-if (!registeredService.matches(token.getService()
+final String serviceId = token.getService().getId();%0A            final OAuthRegisteredService codeRegisteredService =%0A                    OAuth20Utils.getRegisteredOAuthServiceByClientId(this.servicesManager, serviceId);%0A            if (!clientRegisteredService.equals(codeRegisteredService
 )) %7B
@@ -3166,43 +3166,36 @@
     
+    
 code, 
-token.getService().getId(), r
+serviceId, clientR
 egis

Fix the check between the OAuth code and client services (#3260)