All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.slack.api.bolt.middleware.builtin.SingleTeamAuthorization Maven / Gradle / Ivy

There is a newer version: 1.44.2
Show newest version
package com.slack.api.bolt.middleware.builtin;

import com.slack.api.bolt.AppConfig;
import com.slack.api.bolt.context.Context;
import com.slack.api.bolt.middleware.Middleware;
import com.slack.api.bolt.middleware.MiddlewareChain;
import com.slack.api.bolt.model.Installer;
import com.slack.api.bolt.request.Request;
import com.slack.api.bolt.response.Response;
import com.slack.api.bolt.service.InstallationService;
import com.slack.api.methods.MethodsClient;
import com.slack.api.methods.SlackApiException;
import com.slack.api.methods.response.auth.AuthTestResponse;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;

import static com.slack.api.bolt.middleware.MiddlewareOps.isNoAuthRequiredRequest;
import static com.slack.api.bolt.middleware.MiddlewareOps.isNoTokenRequiredRequest;

/**
 * Verifies if the given access token when booting this app is valid for incoming requests.
 */
@Slf4j
public class SingleTeamAuthorization implements Middleware {

    private final AppConfig appConfig;
    private final InstallationService installationService;

    private Optional cachedAuthTestResponse = Optional.empty();
    private AtomicLong lastCachedMillis = new AtomicLong(0L);

    public SingleTeamAuthorization(AppConfig appConfig, InstallationService installationService) {
        this(appConfig, null, installationService);
    }

    public SingleTeamAuthorization(
            AppConfig appConfig,
            AuthTestResponse initialAuthTest,
            InstallationService installationService) {
        this.appConfig = appConfig;
        this.cachedAuthTestResponse = Optional.ofNullable(initialAuthTest);
        this.installationService = installationService;
    }

    @Override
    public Response apply(Request req, Response resp, MiddlewareChain chain) throws Exception {
        if (isNoAuthRequiredRequest(req.getRequestType())) {
            return chain.next(req);
        }
        if (isNoTokenRequiredRequest(req)) {
            // Nothing to do here
            // enterprise_id / team_id are already set by Request object constructor
            return chain.next(req);
        }

        Context context = req.getContext();
        String botToken = context.getBotToken() != null ? context.getBotToken() : appConfig.getSingleTeamBotToken();
        AuthTestResponse authResult = callAuthTest(botToken, appConfig, context.client());
        if (authResult.isOk()) {
            context.setAuthTestResponse(authResult);
            context.setBotToken(botToken);
            Map> botHeaders = authResult.getHttpResponseHeaders();
            List botScopesHeader = botHeaders != null ? botHeaders.get("x-oauth-scopes") : null;
            context.setBotScopes(botScopesHeader != null ? Arrays.asList(botScopesHeader.get(0).split(",")) : null);
            context.setBotUserId(authResult.getUserId());
            context.setTeamId(authResult.getTeamId());
            context.setEnterpriseId(authResult.getEnterpriseId());

            if (appConfig.isAlwaysRequestUserTokenNeeded()) {
                if (installationService == null) {
                    log.warn("Skipped to fetch requestUserToken as InstallationService is not available for SingleTeamAuthorization - " +
                                    "enterprise_id: {}, team_id: {}, user_id: {}",
                            context.getEnterpriseId(), context.getTeamId(), context.getRequestUserId()
                    );
                } else {
                    Installer installer = installationService.findInstaller(
                            context.getEnterpriseId(),
                            context.getTeamId(),
                            context.getRequestUserId()
                    );
                    if (installer != null) {
                        String userToken = installer.getInstallerUserAccessToken();
                        context.setRequestUserToken(userToken);
                        AuthTestResponse userAuthTestResponse = callAuthTest(userToken, appConfig, context.client());
                        Map> userHeaders = userAuthTestResponse.getHttpResponseHeaders();
                        List userScopesHeader = userHeaders != null ? userHeaders.get("x-oauth-scopes") : null;
                        context.setRequestUserScopes(userScopesHeader != null ? Arrays.asList(userScopesHeader.get(0).split(",")) : null);
                    }
                }
            }

            return chain.next(req);
        } else {
            log.info("Invalid request detected - enterprise_id: {}, team_id: {}, user_id: {}",
                    context.getEnterpriseId(), context.getTeamId(), context.getRequestUserId());
            return Response.builder()
                    .statusCode(401)
                    .contentType(Response.CONTENT_TYPE_APPLICATION_JSON_UTF8)
                    .body("{\"error\":\"a request for an unknown workspace detected\"}")
                    .build();
        }
    }

    protected AuthTestResponse callAuthTest(String token, AppConfig config, MethodsClient client) throws IOException, SlackApiException {
        if (cachedAuthTestResponse.isPresent()) {
            boolean permanentCacheEnabled = config.getAuthTestCacheExpirationMillis() < 0;
            if (permanentCacheEnabled) {
                return cachedAuthTestResponse.get();
            }
            long millisToExpire = lastCachedMillis.get() + config.getAuthTestCacheExpirationMillis();
            long currentMillis = System.currentTimeMillis();
            if (millisToExpire > currentMillis) {
                return cachedAuthTestResponse.get();
            }
        }
        AuthTestResponse response = client.authTest(r -> r.token(token));
        cachedAuthTestResponse = Optional.of(response); // response here is non-null for sure
        lastCachedMillis.set(System.currentTimeMillis());
        return response;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy