package com.atlassian.bitbucket.internal.ssh.server;

import com.atlassian.bitbucket.auth.SshAuthenticationContext;
import com.atlassian.bitbucket.auth.SshAuthenticationHandler;
import com.atlassian.bitbucket.ssh.SshConfigurationService;
import com.atlassian.bitbucket.ssh.SshKey;
import com.atlassian.bitbucket.ssh.SshKeyService;
import com.atlassian.bitbucket.user.AbstractApplicationUserVisitor;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.bitbucket.user.DetailedUser;
import com.atlassian.bitbucket.user.ServiceUser;

import javax.annotation.Nonnull;

import static com.atlassian.bitbucket.internal.ssh.SshConstants.LABEL_ACCESS_KEY;

public class DefaultSshAuthenticationHandler implements SshAuthenticationHandler {

    private final SshKeyService sshKeyService;
    private final SshConfigurationService sshConfigurationService;

    public DefaultSshAuthenticationHandler(SshKeyService sshKeyService,
                                           SshConfigurationService sshConfigurationService) {
        this.sshKeyService = sshKeyService;
        this.sshConfigurationService = sshConfigurationService;
    }

    @Override
    public ApplicationUser authenticate(@Nonnull SshAuthenticationContext authenticationContext) {
        SshKey sshKey = sshKeyService.getByPublicKey(authenticationContext.getPublicKey());
        ApplicationUser user = sshKey == null ? null : sshKey.getUser();

        // if the key doesn't exist, its user is orphaned or access keys are enabled there is no reason to probe further
        // we return what we got
        if (user == null || sshConfigurationService.getConfiguration().isAccessKeysEnabled()) {
            return user;
        }

        // access keys are disabled - filter out access key users
        user = user.accept(new AbstractApplicationUserVisitor<ApplicationUser>() {

            @Override
            public ApplicationUser visit(@Nonnull ApplicationUser user) {
                return user;
            }

            @Override
            public ApplicationUser visit(@Nonnull DetailedUser user) {
                return user;
            }

            @Override
            public ApplicationUser visit(@Nonnull ServiceUser user) {
                return LABEL_ACCESS_KEY.equals(user.getLabel()) ? null : user;
            }
        });

        // encode these on the MDC so they can be included in the access logs and included in events
        // but only if authentication succeeded
        if (user != null) {
            new SshKeyDetails(Integer.toString(sshKey.getId()), sshKey.getLabel()).putInMDC();
        }

        return user;
    }
}
