package io.fathom.cloud.openstack.client.identity; import io.fathom.cloud.openstack.client.RestClientException; import io.fathom.cloud.openstack.client.identity.model.RegisterRequest; import io.fathom.cloud.openstack.client.identity.model.RegisterResponse; import io.fathom.cloud.openstack.client.identity.model.V2AuthRequest; import io.fathom.cloud.openstack.client.identity.model.V2AuthResponse; import io.fathom.http.HttpClient; import java.net.URI; import java.security.KeyPair; import javax.security.auth.x500.X500Principal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fathomdb.crypto.CertificateAndKey; import com.google.common.base.Strings; public class CertificateAuthTokenProvider implements TokenProvider { private static final Logger log = LoggerFactory.getLogger(CertificateAuthTokenProvider.class); final OpenstackIdentityClient identityClient; private V2AuthResponse response; final String project; final CertificateAndKey certificateAndKey; public CertificateAuthTokenProvider(OpenstackIdentityClient identityClient, String project, CertificateAndKey certificateAndKey) { this.identityClient = identityClient; this.project = project; this.certificateAndKey = certificateAndKey; } @Override public void reset() { this.response = null; } public V2AuthResponse getResponse() throws RestClientException { if (this.response == null) { V2AuthRequest request = new V2AuthRequest(); request.auth = new V2AuthRequest.V2AuthCredentials(); request.auth.tenantName = project; V2AuthResponse responseChallenge = identityClient.doLogin(request, certificateAndKey); String challenge = responseChallenge.challenge; V2AuthRequest.ChallengeResponse challengeResponse = ChallengeResponses.respondToAuthChallenge( certificateAndKey, challenge); request.auth.challengeResponse = challengeResponse; V2AuthResponse response = identityClient.doLogin(request, certificateAndKey); this.response = response; } return this.response; } @Override public String findEndpoint(String type) throws RestClientException { V2AuthResponse response = getResponse(); if (response.access != null && response.access.serviceCatalog != null) { for (V2AuthResponse.Service service : response.access.serviceCatalog) { if (!service.type.equals(type)) { continue; } for (V2AuthResponse.Endpoint endpoint : service.endpoints) { return endpoint.publicURL; } } } return null; } public static CertificateAuthTokenProvider build(OpenstackIdentityClient identityClient, String project, CertificateAndKey certificateAndKey) { return new CertificateAuthTokenProvider(identityClient, project, certificateAndKey); } @Override public String getToken() throws RestClientException { V2AuthResponse response = getResponse(); if (response == null || response.access == null || response.access.token == null) { log.warn("Unable to get auth token"); return null; } return response.access.token.id; } @Override public HttpClient getHttpClient() { return identityClient.getHttpClient(); } public static OpenstackIdentityClient tryAuth(URI uri, CertificateAndKey certificateAndKey) throws RestClientException { try { OpenstackIdentityClient client = OpenstackIdentityClient.build(uri); String project = null; CertificateAuthTokenProvider tokenProvider = new CertificateAuthTokenProvider(client, project, certificateAndKey); String token = tokenProvider.getToken(); if (token != null) { return client.withTokenProvider(tokenProvider); } return null; } catch (RestClientException e) { if (e.is(401)) { return null; } else { throw e; } } } public static OpenstackIdentityClient ensureRegistered(KeyPair keypair, URI uri, String email) throws RestClientException { CertificateAndKey certificateAndKey = createSelfSigned(keypair, email); OpenstackIdentityClient auth = CertificateAuthTokenProvider.tryAuth(uri, certificateAndKey); if (auth == null) { registerKey(uri, email, certificateAndKey); auth = CertificateAuthTokenProvider.tryAuth(uri, certificateAndKey); if (auth == null) { throw new IllegalStateException("Unable to authenticate after registration"); } } return auth; } public static CertificateAndKey createSelfSigned(KeyPair keypair, String email) { X500Principal subject = new X500Principal("CN=" + email); CertificateAndKey certificateAndKey = ChallengeResponses.createSelfSigned(subject, keypair); return certificateAndKey; } private static void registerKey(URI uri, String email, CertificateAndKey certificateAndKey) throws RestClientException { OpenstackIdentityClient client = OpenstackIdentityClient.build(uri); RegisterRequest registerRequest = new RegisterRequest(); registerRequest.email = email; RegisterResponse registerResponse = client.register(registerRequest, certificateAndKey); V2AuthRequest.ChallengeResponse challengeResponse = ChallengeResponses.respondToRegistrationChallenge( certificateAndKey, registerResponse.challenge); registerRequest.challengeResponse = challengeResponse; registerResponse = client.register(registerRequest, certificateAndKey); if (Strings.isNullOrEmpty(registerResponse.userId)) { throw new RestClientException("Unable to register (invalid response)"); } } }