Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,35 @@ OSClientV3 os = OSFactory.builderV3()
.scopeToProject(Identifier.byId("project id"))
.authenticate());
```
(5) authenticate using client certificate
```bash
openssl pkcs12 -export -out client-certificate-keystore.p12 -inkey key.pem -in cert.pem -certfile ca.pem
Enter Export Password:encrypt
Verifying - Enter Export Password:encrypt
```
```java
String encrypt = "encrypt";
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream(new File("client-certificate-keystore.p12")), encrypt.toCharArray());
SSLContext sslContext = SSLContexts.custom()
//ignore server verify
.loadTrustMaterial(new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
})
.loadKeyMaterial(keyStore,encrypt.toCharArray())
.build();
Config config = Config.newConfig();
config.withSSLContext(sslContext);
OSClient.OSClientV3 osClient = OSFactory.builderV3()
.endpoint("https://<fqdn>:5000/v3")
.withConfig(config)
.scopeToProject(Identifier.byId("project id"))
//.scopeToDomain(Identifier.byId("domain id"))
.authenticate();
```

#### Identity Operations (Keystone) V3

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.openstack4j.api.identity.v3;

import okhttp3.mockwebserver.RecordedRequest;
import org.openstack4j.api.AbstractTest;
import org.openstack4j.api.OSClient;
import org.openstack4j.core.transport.ClientConstants;
import org.openstack4j.model.common.Identifier;
import org.openstack4j.openstack.OSFactory;
import org.testng.annotations.Test;

import static org.testng.Assert.assertEquals;

/**
* Tests the Identity/Keystone API version 3 Keystone tokenless
*/
@Test(groups = "idV3", suiteName = "Identity/V3/Keystone")
public class KeystoneTokenlessTest extends AbstractTest {

private static final String JSON_USERS = "/identity/v3/users.json";
private static final String DOMAIN_ID = "default";

/**
* check headers whether right from request
*
* @throws Exception
*/
public void pass_headers_Test() throws Exception {

respondWith(JSON_USERS);

OSClient.OSClientV3 osClient = OSFactory.builderV3()
.endpoint(authURL("/v3"))
.scopeToDomain(Identifier.byId(DOMAIN_ID))
.authenticate();
osClient.identity().users().list();

RecordedRequest request = server.takeRequest();
assertEquals(request.getHeader(ClientConstants.HEADER_X_DOMAIN_ID), DOMAIN_ID);
}

@Override
protected Service service() {
return Service.IDENTITY;
}
}
9 changes: 9 additions & 0 deletions core/src/main/java/org/openstack4j/api/OSClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.openstack4j.model.identity.v3.Token;
import org.openstack4j.api.magnum.MagnumService;

import java.util.Map;
import java.util.Set;

/**
Expand Down Expand Up @@ -61,6 +62,14 @@ public interface OSClient< T extends OSClient<T>> {
*/
T perspective(Facing perspective);

/**
* Passes the Headers for the current Session(Client)
*
* @param headers the headers to use for keystone tokenless
* @return OSClient for method chaining
*/
T headers(Map<String, ? extends Object> headers);

/**
* Gets the supported services. A set of ServiceTypes will be returned
* identifying the OpenStack services installed and supported
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ public final class ClientConstants {

public static final String HEADER_X_AUTH_TOKEN = "X-Auth-Token";
public static final String HEADER_X_SUBJECT_TOKEN = "X-Subject-Token";
public static final String HEADER_X_PROJECT_ID = "X-Project-Id";
public static final String HEADER_X_PROJECT_NAME = "X-Project-Name";
public static final String HEADER_X_PROJECT_DOMAIN_ID = "X-Project-Domain-Id";
public static final String HEADER_X_PROJECT_DOMAIN_NAME = "X-Project-Domain-Name";
public static final String HEADER_X_DOMAIN_ID = "X-Domain-Id";
public static final String HEADER_X_DOMAIN_NAME = "X-Domain-Name";
public static final String HEADER_CONTENT_LANGUAGE = "Content-Language";
public static final String HEADER_CONTENT_ENCODING = "Content-Encoding";
public static final String HEADER_CONTENT_TYPE = "Content-Type";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.openstack4j.api.types.Facing;
import org.openstack4j.core.transport.Config;
import org.openstack4j.model.common.Identifier;
import org.openstack4j.openstack.common.Auth;
import org.openstack4j.openstack.identity.v2.domain.Credentials;
import org.openstack4j.openstack.identity.v2.domain.RaxApiKeyCredentials;
import org.openstack4j.openstack.identity.v2.domain.TokenAuth;
Expand Down Expand Up @@ -162,7 +163,11 @@ public OSClientV3 authenticate() throws AuthenticationException {
if (tokenId != null && tokenId.length() > 0)
return (OSClientV3) OSAuthenticator.invoke(new KeystoneAuth(tokenId, scope), endpoint, perspective, config,
provider);
return (OSClientV3) OSAuthenticator.invoke(new KeystoneAuth(user, password, domain, scope), endpoint, perspective,
if (user != null && user.length() > 0)
return (OSClientV3) OSAuthenticator.invoke(new KeystoneAuth(user, password, domain, scope), endpoint, perspective,
config, provider);
// Use tokenless auth finally
return (OSClientV3) OSAuthenticator.invoke(new KeystoneAuth(scope, Auth.Type.TOKENLESS), endpoint, perspective,
config, provider);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

public interface Auth extends ModelEntity {

public enum Type { CREDENTIALS, TOKEN, RAX_APIKEY }
public enum Type { CREDENTIALS, TOKEN, RAX_APIKEY, TOKENLESS }

}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ public KeystoneAuth(String user, String password, Identifier domain, AuthScope s
this.type = Type.CREDENTIALS;
}

public KeystoneAuth(AuthScope scope, Type type){
this.scope = scope;
this.type = type;
}

protected KeystoneAuth(Type type) {
this.type = type;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,12 @@ private <R> Invocation<R> builder(Class<R> returnType, String path, HttpMethod m
}
RequestBuilder<R> req = HttpRequest.builder(returnType).endpointTokenProvider(ses).config(ses.getConfig())
.method(method).path(path);
return new Invocation<R>(req, serviceType, endpointFunc);
Map headers = ses.getHeaders();
if (headers != null && headers.size() > 0){
return new Invocation<R>(req, serviceType, endpointFunc).headers(headers);
}else{
return new Invocation<R>(req, serviceType, endpointFunc);
}
}

protected static class Invocation<R> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.openstack4j.core.transport.internal.HttpExecutor;
import org.openstack4j.model.identity.AuthStore;
import org.openstack4j.model.identity.AuthVersion;
import org.openstack4j.model.identity.v3.Authentication;
import org.openstack4j.model.identity.v3.Token;
import org.openstack4j.openstack.common.Auth;
import org.openstack4j.openstack.common.Auth.Type;
Expand All @@ -25,6 +26,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
* Responsible for authenticating and re-authenticating sessions for V2 and V3
* of the Identity API
Expand Down Expand Up @@ -147,6 +151,35 @@ private static OSClientV2 authenticateV2(org.openstack4j.openstack.identity.v2.d
}

private static OSClientV3 authenticateV3(KeystoneAuth auth, SessionInfo info, Config config) {
if (auth.getType().equals(Type.TOKENLESS)){
Map headers = new HashMap();
Authentication.Scope.Project project = auth.getScope().getProject();
if (project != null){
if (!isEmpty(project.getId()))
headers.put(ClientConstants.HEADER_X_PROJECT_ID, project.getId());
if (!isEmpty(project.getName()))
headers.put(ClientConstants.HEADER_X_PROJECT_NAME, project.getName());
Authentication.Scope.Domain domain = project.getDomain();
if (domain != null){
if (!isEmpty(domain.getId()))
headers.put(ClientConstants.HEADER_X_PROJECT_DOMAIN_ID, domain.getId());
if (!isEmpty(domain.getName()))
headers.put(ClientConstants.HEADER_X_PROJECT_DOMAIN_NAME, domain.getName());
}
}else{
Authentication.Scope.Domain domain = auth.getScope().getDomain();
if (domain != null){
if (!isEmpty(domain.getId()))
headers.put(ClientConstants.HEADER_X_DOMAIN_ID, domain.getId());
if (!isEmpty(domain.getName()))
headers.put(ClientConstants.HEADER_X_DOMAIN_NAME, domain.getName());
}
}
KeystoneToken keystoneToken = new KeystoneToken();
keystoneToken.setEndpoint(info.endpoint);
return OSClientSessionV3.createSession(keystoneToken, null, null, config).headers(headers);
}

HttpRequest<KeystoneToken> request = HttpRequest.builder(KeystoneToken.class)
.header(ClientConstants.HEADER_OS4J_AUTH, TOKEN_INDICATOR).endpoint(info.endpoint)
.method(HttpMethod.POST).path("/auth/tokens").config(config).entity(auth).build();
Expand Down Expand Up @@ -203,4 +236,10 @@ private static class SessionInfo {
this.provider = provider;
}
}

private static boolean isEmpty(String str){
if (str != null && str.length() > 0)
return false;
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Set;

/**
Expand All @@ -61,6 +62,7 @@ public abstract class OSClientSession<R, T extends OSClient<T>> implements Endpo
String region;
Set<ServiceType> supports;
CloudProvider provider;
Map<String, ? extends Object> headers;
EndpointURLResolver fallbackEndpointUrlResolver = new DefaultEndpointURLResolver();

@SuppressWarnings("rawtypes")
Expand Down Expand Up @@ -227,6 +229,18 @@ public CloudProvider getProvider() {
return (provider == null) ? CloudProvider.UNKNOWN : provider;
}

/**
* {@inheritDoc}
*/
public T headers(Map<String, ? extends Object> headers) {
this.headers = headers;
return (T) this;
}

public Map<String, ? extends Object> getHeaders(){
return this.headers;
}

/**
* {@inheritDoc}
*/
Expand Down