Skip to content

Commit

Permalink
Fix fabric8io#2111: Add Support for OIDC token refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
rohanKanojia committed Sep 1, 2020
1 parent 935224a commit aacd0e6
Show file tree
Hide file tree
Showing 9 changed files with 780 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#### Dependency Upgrade

#### New Features
* Fix #2111: Support automatic refreshing for expired OIDC tokens

### 4.11.0 (2020-08-26)
#### Bugs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ private static boolean tryKubeConfig(Config config, String context) {
return true;
}

private static String getKubeconfigFilename() {
public static String getKubeconfigFilename() {
String fileName = Utils.getSystemPropertyOrEnvVar(KUBERNETES_KUBECONFIG_FILE, new File(getHomeDir(), ".kube" + File.separator + "config").toString());

// if system property/env var contains multiple files take the first one based on the environment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
* like <code>osc login</code> and <code>osc project myproject</code>
*/
public class KubeConfigUtils {
private KubeConfigUtils() {}

public static Config parseConfig(File file) throws IOException {
ObjectMapper mapper = Serialization.yamlMapper();
return mapper.readValue(file, Config.class);
Expand Down Expand Up @@ -66,8 +68,6 @@ public static NamedContext getCurrentContext(Config config) {
return null;
}

/**
*/
/**
* Returns the current user token for the config and current context
*
Expand Down Expand Up @@ -97,11 +97,11 @@ public static AuthInfo getUserAuthInfo(Config config, Context context) {
if (user != null) {
List<NamedAuthInfo> users = config.getUsers();
if (users != null) {
for (NamedAuthInfo namedAuthInfo : users) {
if (user.equals(namedAuthInfo.getName())) {
authInfo = namedAuthInfo.getUser();
}
}
authInfo = users.stream()
.filter(u -> u.getName().equals(user))
.findAny()
.map(NamedAuthInfo::getUser)
.orElse(null);
}
}
}
Expand All @@ -122,14 +122,41 @@ public static Cluster getCluster(Config config, Context context) {
if (clusterName != null) {
List<NamedCluster> clusters = config.getClusters();
if (clusters != null) {
for (NamedCluster namedCluster : clusters) {
if (clusterName.equals(namedCluster.getName())) {
cluster = namedCluster.getCluster();
}
}
cluster = clusters.stream()
.filter(c -> c.getName().equals(clusterName))
.findAny()
.map(NamedCluster::getCluster)
.orElse(null);
}
}
}
return cluster;
}

/**
* Get User index from Config object
*
* @param config {@link io.fabric8.kubernetes.api.model.Config} Kube Config
* @param userName username inside Config
* @return index of user in users array
*/
public static int getNamedUserIndexFromConfig(Config config, String userName) {
for (int i = 0; i < config.getUsers().size(); i++) {
if (config.getUsers().get(i).getName().equals(userName)) {
return i;
}
}
return -1;
}

/**
* Modify KUBECONFIG file
*
* @param kubeConfig modified {@link io.fabric8.kubernetes.api.model.Config} object
* @param kubeConfigPath path to KUBECONFIG
* @throws IOException in case of failure while writing to file
*/
public static void persistKubeConfigIntoFile(Config kubeConfig, String kubeConfigPath) throws IOException {
Serialization.yamlMapper().writeValue(new File(kubeConfigPath), kubeConfig);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
*/
package io.fabric8.kubernetes.client.utils;

import io.fabric8.kubernetes.api.model.AuthInfo;
import io.fabric8.kubernetes.api.model.ListOptions;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.internal.KubeConfigUtils;
import io.fabric8.kubernetes.client.internal.SSLUtils;
import okhttp3.*;
import okhttp3.logging.HttpLoggingInterceptor;
Expand All @@ -28,6 +30,8 @@
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
Expand All @@ -47,6 +51,7 @@

public class HttpClientUtils {

public static final String AUTHORIZATION = "Authorization";
private static Pattern VALID_IPV4_PATTERN = null;
public static final String ipv4Pattern = "(http:\\/\\/|https:\\/\\/)?(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])(\\/[0-9]\\d|1[0-9]\\d|2[0-9]\\d|3[0-2]\\d)?";
private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
Expand Down Expand Up @@ -140,11 +145,23 @@ private static OkHttpClient createHttpClient(final Config config, final Consumer
httpClientBuilder.addInterceptor(chain -> {
Request request = chain.request();
if (Utils.isNotNullOrEmpty(config.getUsername()) && Utils.isNotNullOrEmpty(config.getPassword())) {
Request authReq = chain.request().newBuilder().addHeader("Authorization", Credentials.basic(config.getUsername(), config.getPassword())).build();
Request authReq = chain.request().newBuilder().addHeader(AUTHORIZATION, Credentials.basic(config.getUsername(), config.getPassword())).build();
return chain.proceed(authReq);
} else if (Utils.isNotNullOrEmpty(config.getOauthToken())) {
Request authReq = chain.request().newBuilder().addHeader("Authorization", "Bearer " + config.getOauthToken()).build();
return chain.proceed(authReq);
Request authReq = chain.request().newBuilder().addHeader(AUTHORIZATION, "Bearer " + config.getOauthToken()).build();
Response response = chain.proceed(authReq);
if (response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) {
io.fabric8.kubernetes.api.model.Config kubeConfig = KubeConfigUtils.parseConfig(new File(Config.getKubeconfigFilename()));
AuthInfo currentAuthInfo = KubeConfigUtils.getUserAuthInfo(kubeConfig, config.getCurrentContext().getContext());
// Check if AuthProvider is set or not
if (currentAuthInfo.getAuthProvider() != null) {
String newAccessToken = OpenIDConnectionUtils.resolveOIDCTokenFromAuthConfig(currentAuthInfo.getAuthProvider().getConfig());
config.setOauthToken(newAccessToken);
Request authReqWithUpdatedToken = chain.request().newBuilder().addHeader(AUTHORIZATION, "Bearer " + config.getOauthToken()).build();
return chain.proceed(authReqWithUpdatedToken);
}
}
return response;
}
return chain.proceed(request);
}).addInterceptor(new ImpersonatorInterceptor(config))
Expand Down
Loading

0 comments on commit aacd0e6

Please sign in to comment.