org.cicomponents.github.impl.GithubOAuthTokenProvisioner.java Source code

Java tutorial

Introduction

Here is the source code for org.cicomponents.github.impl.GithubOAuthTokenProvisioner.java

Source

/**
 * Copyright (c) 2016, All Contributors (see CONTRIBUTORS file)
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package org.cicomponents.github.impl;

import com.github.scribejava.apis.GitHubApi;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.oauth.OAuth20Service;
import com.google.common.collect.Iterables;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.cicomponents.PersistentMap;
import org.cicomponents.github.GithubApplicationCredentialsProvider;
import org.cicomponents.github.GithubOAuthTokenProvider;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.*;
import org.osgi.service.component.annotations.Component;

import java.awt.Desktop;
import java.net.URI;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
@Component(immediate = true, scope = ServiceScope.SINGLETON)
public class GithubOAuthTokenProvisioner implements GithubOAuthFinalizer {

    @Reference
    protected PersistentMap persistentMap;

    private ComponentContext context;

    @Activate
    protected void activate(ComponentContext context) {
        this.context = context;
    }

    private Map<UUID, Collection<OAuthTokenProvider>> registrations = new HashMap<>();

    @SneakyThrows
    @Override
    public void finalizeOAuth(UUID uuid, String code) {
        Collection<OAuthTokenProvider> providers = registrations.get(uuid);
        providers.forEach(new Consumer<OAuthTokenProvider>() {
            @SneakyThrows
            @Override
            public void accept(OAuthTokenProvider p) {
                p.setToken(p.getService().getAccessToken(code));
            }
        });
        ArrayList<String> tokens = new ArrayList<>(
                providers.stream().map(OAuthTokenProvider::getAccessToken).collect(Collectors.toList()));
        persistentMap.put(Iterables.getLast(providers).getCredentialsProvider().getClientId(), tokens);
        Collection<ServiceRegistration<GithubOAuthTokenProvider>> registrations = registerProviders(providers);
        this.registrations.remove(uuid);
        tokenProviders.addAll(registrations);
        providers.forEach(p -> pendingProvisioning.remove(p.getCredentialsProvider().getClientId()));
    }

    private Collection<ServiceRegistration<GithubOAuthTokenProvider>> registerProviders(
            Collection<OAuthTokenProvider> providers) {
        return providers.stream().map(p -> {
            Hashtable<String, Object> props = new Hashtable<>();
            props.put("github-repository", p.getRepository());
            ServiceRegistration<GithubOAuthTokenProvider> registration = context.getBundleContext()
                    .registerService(GithubOAuthTokenProvider.class, p, props);
            return registration;
        }).collect(Collectors.toList());
    }

    private Collection<ServiceRegistration<GithubOAuthTokenProvider>> tokenProviders = new ArrayList<>();

    private Set<String> pendingProvisioning = new HashSet<>();

    private static class OAuthTokenProvider implements GithubOAuthTokenProvider {
        @Getter
        private final GithubApplicationCredentialsProvider credentialsProvider;
        @Getter
        private OAuth20Service service;
        @Getter
        private final String repository;

        @Getter
        @Setter
        private OAuth2AccessToken token;

        private OAuthTokenProvider(GithubApplicationCredentialsProvider credentialsProvider,
                OAuth20Service oAuth20Service, String repository) {
            this.credentialsProvider = credentialsProvider;
            service = oAuth20Service;
            this.repository = repository;
        }

        private OAuthTokenProvider(GithubApplicationCredentialsProvider credentialsProvider,
                OAuth2AccessToken token, String repository) {
            this.credentialsProvider = credentialsProvider;
            this.token = token;
            this.repository = repository;
        }

        @SneakyThrows
        public String getAccessToken() {
            return token.getAccessToken();
        }
    }

    @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
    @SneakyThrows
    @Synchronized("registrations")
    protected void addApplicationCredentialsProvider(GithubApplicationCredentialsProvider provider) {
        ArrayList<String> tokens = (ArrayList<String>) persistentMap.get(provider.getClientId());
        if (tokens == null) {
            if (pendingProvisioning.contains(provider.getClientId())) {
                return;
            }
            pendingProvisioning.add(provider.getClientId());
            UUID uuid = UUID.randomUUID();
            OAuth20Service service = new ServiceBuilder().apiKey(provider.getClientId())
                    .apiSecret(provider.getClientSecret()).scope("write:repo_hook, read:repo_hook, repo")
                    .state(uuid.toString()).callback("") // use GitHub's configured value
                    .build(GitHubApi.instance());

            String authorizationUrl = service.getAuthorizationUrl();

            log.info("Open the following URL to authorize GitHub repo access: {}", authorizationUrl);
            System.out.println("Open the following URL to authorize GitHub access: " + authorizationUrl);
            if (Desktop.isDesktopSupported()) {
                Desktop.getDesktop().browse(URI.create(authorizationUrl));
            }

            List<OAuthTokenProvider> providers = provider.getRepositories().stream()
                    .map(r -> new OAuthTokenProvider(provider, service, r)).collect(Collectors.toList());

            registrations.put(uuid, providers);
        } else {
            List<OAuthTokenProvider> providers = IntStream
                    .range(0, provider.getRepositories().size()).mapToObj(i -> new OAuthTokenProvider(provider,
                            new OAuth2AccessToken(tokens.get(i)), provider.getRepositories().get(i)))
                    .collect(Collectors.toList());
            tokenProviders.addAll(registerProviders(providers));
        }
    }

    @Synchronized("registrations")
    protected void removeApplicationCredentialsProvider(GithubApplicationCredentialsProvider provider) {
    }
}