blob: 2775a8a043ee39fdd7d3587aa9db3eabb7720845 [file] [log] [blame]
package org.csanchez.jenkins.plugins.kubernetes;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
import hudson.Extension;
import hudson.util.Secret;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Base64InputStream;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ProtocolException;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.kohsuke.stapler.DataBoundConstructor;
import javax.net.ssl.HostnameVerifier;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
*/
public class OpenShiftBearerTokenCredentialImpl extends UsernamePasswordCredentialsImpl implements TokenProducer {
private transient AtomicReference<Token> token = new AtomicReference<Token>();
@DataBoundConstructor
public OpenShiftBearerTokenCredentialImpl(CredentialsScope scope, String id, String description, String username, String password) {
super(scope, id, description, username, password);
}
private Object readResolve() {
token = new AtomicReference<Token>();
return this;
}
@Override
public String getToken(String serviceAddress, String caCertData, boolean skipTlsVerify) throws IOException {
Token t = this.token.get();
if (t == null || System.currentTimeMillis() > t.expire) {
t = refreshToken(serviceAddress, caCertData, skipTlsVerify);
}
return t.value;
}
private synchronized Token refreshToken(String serviceAddress, String caCertData, boolean skipTlsVerify) throws IOException {
URI uri = null;
try {
uri = new URI(serviceAddress);
} catch (URISyntaxException e) {
throw new IOException("Invalid server URL "+serviceAddress, e);
}
final HttpClientBuilder builder = HttpClients.custom()
.setRedirectStrategy(NO_REDIRECT);
if (skipTlsVerify || caCertData != null) {
final SSLContextBuilder sslBuilder = new SSLContextBuilder();
HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
try {
if (skipTlsVerify) {
sslBuilder.loadTrustMaterial(null, ALWAYS);
hostnameVerifier = NoopHostnameVerifier.INSTANCE;
}
else if (caCertData != null) {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
CertificateFactory f = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) f.generateCertificate(new Base64InputStream(new ByteArrayInputStream(caCertData.getBytes())));
ks.setCertificateEntry(uri.getHost(), cert);
sslBuilder.loadTrustMaterial(ks, null);
}
builder.setSSLSocketFactory(new SSLConnectionSocketFactory(sslBuilder.build(), hostnameVerifier));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
HttpGet authorize = new HttpGet(serviceAddress + "/oauth/authorize?client_id=openshift-challenging-client&response_type=token");
authorize.setHeader("Authorization", "Basic "+ Base64.encodeBase64String(
(getUsername()+':'+Secret.toString(getPassword()))
.getBytes()));
final CloseableHttpResponse response = builder.build().execute(authorize);
if (response.getStatusLine().getStatusCode() != 302) {
throw new IOException("Failed to get an OAuth access token " + response.getStatusLine().getStatusCode());
}
String location = response.getFirstHeader("Location").getValue();
String parameters = location.substring(location.indexOf('#')+1);
List<NameValuePair> pairs = URLEncodedUtils.parse(parameters, Charset.forName("UTF-8"));
Token t = new Token();
for (NameValuePair pair : pairs) {
if (pair.getName().equals("access_token")) {
t.value = pair.getValue();
}
else if (pair.getName().equals("expires_in")) {
t.expire = System.currentTimeMillis() + Long.parseLong(pair.getValue())*1000 - 100;
}
}
return t;
}
@Extension
public static class DescriptorImpl extends BaseStandardCredentialsDescriptor {
@Override
public String getDisplayName() {
return "OpenShift OAuth Access token";
}
}
private static class Token {
String value;
long expire;
}
private static TrustStrategy ALWAYS = new TrustStrategy() {
@Override
public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
return true;
}
};
private static RedirectStrategy NO_REDIRECT = new RedirectStrategy() {
@Override
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
return false;
}
@Override
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
return null;
}
};
}