/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.security.oauth; import com.google.api.client.util.store.MemoryDataStoreFactory; import org.eclipse.che.api.auth.shared.dto.OAuthToken; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.commons.json.JsonHelper; import org.eclipse.che.commons.json.JsonParseException; import org.eclipse.che.security.oauth.shared.User; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.URL; import static com.google.api.client.repackaged.com.google.common.base.Strings.isNullOrEmpty; /** OAuth authentication for github account. */ @Singleton public class GitHubOAuthAuthenticator extends OAuthAuthenticator { @Inject public GitHubOAuthAuthenticator(@Nullable @Named("oauth.github.clientid") String clientId, @Nullable @Named("oauth.github.clientsecret") String clientSecret, @Nullable @Named("oauth.github.redirecturis") String[] redirectUris, @Nullable @Named("oauth.github.authuri") String authUri, @Nullable @Named("oauth.github.tokenuri") String tokenUri) throws IOException { if (!isNullOrEmpty(clientId) && !isNullOrEmpty(clientSecret) && !isNullOrEmpty(authUri) && !isNullOrEmpty(tokenUri) && redirectUris != null && redirectUris.length != 0) { configure(clientId, clientSecret, redirectUris, authUri, tokenUri, new MemoryDataStoreFactory()); } } @Override public User getUser(OAuthToken accessToken) throws OAuthAuthenticationException { GitHubUser user = getJson("https://api.github.com/user?access_token=" + accessToken.getToken(), GitHubUser.class); GithubEmail[] result = getJson2("https://api.github.com/user/emails?access_token=" + accessToken.getToken(), GithubEmail[].class, null); GithubEmail verifiedEmail = null; for (GithubEmail email : result) { if (email.isPrimary() && email.isVerified()) { verifiedEmail = email; break; } } if (verifiedEmail == null || verifiedEmail.getEmail() == null || verifiedEmail.getEmail().isEmpty()) { throw new OAuthAuthenticationException( "Sorry, we failed to find any verified emails associated with your GitHub account." + " Please, verify at least one email in your GitHub account and try to connect with GitHub again."); } user.setEmail(verifiedEmail.getEmail()); final String email = user.getEmail(); try { new InternetAddress(email).validate(); } catch (AddressException e) { throw new OAuthAuthenticationException(e.getMessage()); } return user; } protected <O> O getJson2(String getUserUrl, Class<O> userClass, Type type) throws OAuthAuthenticationException { HttpURLConnection urlConnection = null; InputStream urlInputStream = null; try { urlConnection = (HttpURLConnection)new URL(getUserUrl).openConnection(); urlConnection.setRequestProperty("Accept", "application/vnd.github.v3.html+json"); urlInputStream = urlConnection.getInputStream(); return JsonHelper.fromJson(urlInputStream, userClass, type); } catch (JsonParseException | IOException e) { throw new OAuthAuthenticationException(e.getMessage(), e); } finally { if (urlInputStream != null) { try { urlInputStream.close(); } catch (IOException ignored) { } } if (urlConnection != null) { urlConnection.disconnect(); } } } @Override public final String getOAuthProvider() { return "github"; } @Override public OAuthToken getToken(String userId) throws IOException { final OAuthToken token = super.getToken(userId); if (!(token == null || token.getToken() == null || token.getToken().isEmpty())) { // Need to check if token which stored is valid for requests, then if valid - we returns it to caller String tokenVerifyUrl = "https://api.github.com/?access_token=" + token.getToken(); HttpURLConnection http = null; try { http = (HttpURLConnection)new URL(tokenVerifyUrl).openConnection(); http.setInstanceFollowRedirects(false); http.setRequestMethod("GET"); http.setRequestProperty("Accept", "application/json"); if (http.getResponseCode() == 401) { return null; } } finally { if (http != null) { http.disconnect(); } } return token; } return null; } /** * information for each email address indicating if the address * has been verified and if it’s the user’s primary email address for GitHub. */ public static class GithubEmail { private boolean primary; private boolean verified; private String email; public boolean isPrimary() { return primary; } public void setPrimary(boolean primary) { this.primary = primary; } public boolean isVerified() { return verified; } public void setVerified(boolean verified) { this.verified = verified; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } }