<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.jackrabbit.oak.spi.security.authentication.external.impl.jmx;

import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.security.auth.Subject;

import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterators;
import org.apache.jackrabbit.api.JackrabbitRepository;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.commons.json.JsonUtil;
import org.apache.jackrabbit.oak.spi.security.authentication.SystemSubject;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentity;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityException;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityProvider;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalUser;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncContext;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncException;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncHandler;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncResult;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncedIdentity;
import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncResultImpl;
import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncedIdentity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

final class Delegatee {

    private static final Logger log = LoggerFactory.getLogger(Delegatee.class);

    private static final String ERROR_CREATE_DELEGATEE = "Unable to create delegatee";
    private static final String ERROR_SYNC_USER = "Error while syncing user {}";

    private final SyncHandler handler;
    private final ExternalIdentityProvider idp;
    private final UserManager userMgr;
    private final Session systemSession;

    private SyncContext context;

    private Delegatee(@Nonnull SyncHandler handler, @Nonnull ExternalIdentityProvider idp,
                      @Nonnull JackrabbitSession systemSession) throws SyncException, RepositoryException {
        this.handler = handler;
        this.idp = idp;

        this.systemSession = systemSession;
        this.userMgr = systemSession.getUserManager();
        this.context = handler.createContext(idp, userMgr, systemSession.getValueFactory());

        log.info("Created delegatee for SyncMBean with session: {} {}", systemSession, systemSession.getUserID());
    }

    static Delegatee createInstance(@Nonnull final Repository repository, @Nonnull SyncHandler handler, @Nonnull ExternalIdentityProvider idp) {
        Session systemSession;
        try {
            systemSession = Subject.doAs(SystemSubject.INSTANCE, new PrivilegedExceptionAction<Session>() {
                @Override
                public Session run() throws RepositoryException {
                    if (repository instanceof JackrabbitRepository) {
                        // this is to bypass GuestCredentials injection in the "AbstractSlingRepository2"
                        return ((JackrabbitRepository) repository).login(null, null, null);
                    } else {
                        return repository.login(null, null);
                    }
                }
            });
        } catch (PrivilegedActionException e) {
            throw new SyncRuntimeException(ERROR_CREATE_DELEGATEE, e);
        }

        if (!(systemSession instanceof JackrabbitSession)) {
            systemSession.logout();
            throw new SyncRuntimeException("Unable to create SyncContext: JackrabbitSession required.");
        }
        try {
            return new Delegatee(handler, idp, (JackrabbitSession) systemSession);
        } catch (RepositoryException e) {
            systemSession.logout();
            throw new SyncRuntimeException(ERROR_CREATE_DELEGATEE, e);
        } catch (SyncException e) {
            systemSession.logout();
            throw new SyncRuntimeException(ERROR_CREATE_DELEGATEE, e);
        }
    }

    void close() {
        if (context != null) {
            context.close();
            context = null;
        }
        if (systemSession.isLive()) {
            systemSession.logout();
        }
    }

    /**
     * @see SynchronizationMBean#syncUsers(String[], boolean, boolean)
     */
    @Nonnull
    String[] syncUsers(@Nonnull String[] userIds, boolean purge, boolean forceGroupSync) {
        context.setKeepMissing(!purge)
                .setForceGroupSync(forceGroupSync)
                .setForceUserSync(true);
        List<String> list = new ArrayList<String>();
        for (String userId: userIds) {
            try {
                append(list, syncUser(userId));
            } catch (SyncException e) {
                log.warn(ERROR_SYNC_USER, userId, e);
                append(list, new DefaultSyncedIdentity(userId, null, false, -1), e);
            }
        }
        return list.toArray(new String[list.size()]);
    }

    /**
     * @see SynchronizationMBean#syncAllUsers(boolean, boolean)
     */
    @Nonnull
    String[] syncAllUsers(boolean purge, boolean forceGroupSync) {
        try {
            List<String> list = new ArrayList<String>();
            context.setKeepMissing(!purge)
                    .setForceGroupSync(forceGroupSync)
                    .setForceUserSync(true);
            Iterator<SyncedIdentity> iter = handler.listIdentities(userMgr);
            while (iter.hasNext()) {
                SyncedIdentity id = iter.next();
                if (isMyIDP(id)) {
                    try {
                        append(list, syncUser(id.getId()));
                    } catch (SyncException e) {
                        log.error(ERROR_SYNC_USER, id, e);
                        append(list, id, e);
                    }<commit_msg>minor improvement: fix indention<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.jackrabbit.oak.spi.security.authentication.external.impl.jmx;

import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.security.auth.Subject;

import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterators;
import org.apache.jackrabbit.api.JackrabbitRepository;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.commons.json.JsonUtil;
import org.apache.jackrabbit.oak.spi.security.authentication.SystemSubject;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentity;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityException;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityProvider;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalUser;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncContext;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncException;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncHandler;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncResult;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncedIdentity;
import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncResultImpl;
import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncedIdentity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

final class Delegatee {

    private static final Logger log = LoggerFactory.getLogger(Delegatee.class);

    private static final String ERROR_CREATE_DELEGATEE = "Unable to create delegatee";
    private static final String ERROR_SYNC_USER = "Error while syncing user {}";

    private final SyncHandler handler;
    private final ExternalIdentityProvider idp;
    private final UserManager userMgr;
    private final Session systemSession;

    private SyncContext context;

    private Delegatee(@Nonnull SyncHandler handler, @Nonnull ExternalIdentityProvider idp,
                      @Nonnull JackrabbitSession systemSession) throws SyncException, RepositoryException {
        this.handler = handler;
        this.idp = idp;

        this.systemSession = systemSession;
        this.userMgr = systemSession.getUserManager();
        this.context = handler.createContext(idp, userMgr, systemSession.getValueFactory());

        log.info("Created delegatee for SyncMBean with session: {} {}", systemSession, systemSession.getUserID());
    }

    static Delegatee createInstance(@Nonnull final Repository repository, @Nonnull SyncHandler handler, @Nonnull ExternalIdentityProvider idp) {
        Session systemSession;
        try {
            systemSession = Subject.doAs(SystemSubject.INSTANCE, new PrivilegedExceptionAction<Session>() {
                @Override
                public Session run() throws RepositoryException {
                    if (repository instanceof JackrabbitRepository) {
                        // this is to bypass GuestCredentials injection in the "AbstractSlingRepository2"
                        return ((JackrabbitRepository) repository).login(null, null, null);
                    } else {
                        return repository.login(null, null);
                    }
                }
            });
        } catch (PrivilegedActionException e) {
            throw new SyncRuntimeException(ERROR_CREATE_DELEGATEE, e);
        }

        if (!(systemSession instanceof JackrabbitSession)) {
            systemSession.logout();
            throw new SyncRuntimeException("Unable to create SyncContext: JackrabbitSession required.");
        }
        try {
            return new Delegatee(handler, idp, (JackrabbitSession) systemSession);
        } catch (RepositoryException e) {
            systemSession.logout();
            throw new SyncRuntimeException(ERROR_CREATE_DELEGATEE, e);
        } catch (SyncException e) {
            systemSession.logout();
            throw new SyncRuntimeException(ERROR_CREATE_DELEGATEE, e);
        }
    }

    void close() {
        if (context != null) {
            context.close();
            context = null;
        }
        if (systemSession.isLive()) {
            systemSession.logout();
        }
    }

    /**
     * @see SynchronizationMBean#syncUsers(String[], boolean, boolean)
     */
    @Nonnull
    String[] syncUsers(@Nonnull String[] userIds, boolean purge, boolean forceGroupSync) {
        context.setKeepMissing(!purge)
                .setForceGroupSync(forceGroupSync)
                .setForceUserSync(true);
        List<String> list = new ArrayList<String>();
        for (String userId : userIds) {
            try {
                append(list, syncUser(userId));
            } catch (SyncException e) {
                log.warn(ERROR_SYNC_USER, userId, e);
                append(list, new DefaultSyncedIdentity(userId, null, false, -1), e);
            }
        }
        return list.toArray(new String[list.size()]);
    }

    /**
     * @see SynchronizationMBean#syncAllUsers(boolean, boolean)
     */
    @Nonnull
    String[] syncAllUsers(boolean purge, boolean forceGroupSync) {
        try {
            List<String> list = new ArrayList<String>();
            context.setKeepMissing(!purge)
                    .setForceGroupSync(forceGroupSync)
                    .setForceUserSync(true);
            Iterator<SyncedIdentity> iter = handler.listIdentities(userMgr);
            while (iter.hasNext()) {
                SyncedIdentity id = iter.next();
                if (isMyIDP(id)) {
                    try {
                        append(list, syncUser(id.getId()));
                    } catch (SyncException e) {
                        log.error(ERROR_SYNC_USER, id, e);
                        append(list, id, e);
                    }
{'fraction_non_alphanumeric': 0.0893054786939679, 'fraction_numerical': 0.0011068068622025456, 'mean_word_length': 2.9317378297525156, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5402088', 'n_tokens_mistral': 3821, 'n_tokens_neox': 3690, 'n_words': 889}