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
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2020 The SoftLayer Developer Network
Copyright (c) 2021 The SoftLayer Developer Network

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,45 @@ additions to the SoftLayer API.
<dependency>
<groupId>com.softlayer.api</groupId>
<artifactId>softlayer-api-client</artifactId>
<version>0.3.1</version>
<version>0.3.2</version>
</dependency>
```

### Gradle

```groovy
implementation 'com.softlayer.api:softlayer-api-client:0.3.1'
implementation 'com.softlayer.api:softlayer-api-client:0.3.2'
```

### Kotlin

```kotlin
compile("com.softlayer.api:softlayer-api-client:0.3.1")
compile("com.softlayer.api:softlayer-api-client:0.3.2")
```

### Creating a Client

All clients are instances of `ApiClient`. Currently there is only one implementation, the `RestApiClient`. Simply
instantiate it and provide your credentials:


#### Username and API Key
For using a Classic Infrastructure or IBM Cloud API key. When using the IBM Cloud Api key, your username is the literal string `apikey`, more information about that can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#cloud-api) article.

```java
import com.softlayer.api.*;

ApiClient client = new RestApiClient().withCredentials("my user", "my api key");
```

#### Access Token
Information on how to get a temoprary api token can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#temp-token) article.

```java
import com.softlayer.api.*;
ApiClient client = new RestApiClient().withBearerToken("qqqqwwwweeeaaassddd....");
```

If the end point isn't at the normal SoftLayer API, you can provide the prefix to the constructor of the
`RestApiClient`. By default it is set to the public API endpoint, `https://api.softlayer.com/rest/v3.1/`.

Expand Down Expand Up @@ -296,4 +308,4 @@ fully qualified class name of your implementation on a single line in a file in

## Copyright

This software is Copyright (c) 2020 The SoftLayer Developer Network. See the bundled LICENSE file for more information.
This software is Copyright (c) 2021 The SoftLayer Developer Network. See the bundled LICENSE file for more information.
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<artifactId>softlayer-api-client-examples</artifactId>
<packaging>jar</packaging>
<!-- Please keep version in sync with README -->
<version>0.3.1</version>
<version>0.3.2</version>
<name>softlayer-api-client-examples</name>
<url>http://sldn.softlayer.com</url>
<licenses>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ public void start(String[] args) throws Exception {
baseUrl += '/';
}

run(new RestApiClient(baseUrl).withCredentials(args[0], args[1]));
RestApiClient client;
// mvn -e -q compile exec:java -Dexec.args="QuickTest Bearer eyJraWQ.....
if (args[0].trim().equals("Bearer")) {
client = new RestApiClient(baseUrl).withBearerToken(args[1]);
} else {
client = new RestApiClient(baseUrl).withCredentials(args[0], args[1]);
}
run(client);
}

/** Run the example with the given client */
Expand Down
28 changes: 28 additions & 0 deletions examples/src/main/java/com/softlayer/api/example/QuickTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.softlayer.api.example;

import com.softlayer.api.ApiClient;
import com.softlayer.api.RestApiClient;
import com.softlayer.api.service.Account;


/** A quick example for testing if authentication works.

cd softlayer-java/examples
mvn -e -q compile exec:java -Dexec.args="QuickTest Bearer eyJraWQ.....
*/
public class QuickTest extends Example {

@Override
public void run(ApiClient client) throws Exception {
client.withLoggingEnabled();
System.out.format("Authorization: %s\n", client.getCredentials());
Account.Service service = Account.service(client);

Account account = service.getObject();
System.out.format("Account Name: %s\n", account.getCompanyName());
}

public static void main(String[] args) throws Exception {
new QuickTest().start(args);
}
}
2 changes: 1 addition & 1 deletion gen/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<artifactId>softlayer-api-client-gen</artifactId>
<packaging>jar</packaging>
<!-- Please keep version in sync with README -->
<version>0.3.1</version>
<version>0.3.2</version>
<name>softlayer-api-client-gen</name>
<url>http://sldn.softlayer.com</url>
<licenses>
Expand Down
28 changes: 26 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<artifactId>softlayer-api-client</artifactId>
<packaging>jar</packaging>
<!-- Please keep version in sync with README -->
<version>0.3.1</version>
<version>0.3.2</version>
<name>SoftLayer API Client for Java</name>
<description>API client for accessing the SoftLayer API</description>
<url>http://sldn.softlayer.com</url>
Expand Down Expand Up @@ -40,7 +40,7 @@
<connection>scm:git:git@github.com:softlayer/softlayer-java.git</connection>
<developerConnection>scm:git:git@github.com:softlayer/softlayer-java.git</developerConnection>
<url>git@github.com:softlayer/softlayer-java.git</url>
<tag>0.3.1</tag>
<tag>0.3.2</tag>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down Expand Up @@ -161,6 +161,30 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version>
<configuration>
<excludes>
<exclude>**/*com/softlayer/api/service/**/*</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
25 changes: 24 additions & 1 deletion src/main/java/com/softlayer/api/ApiClient.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.softlayer.api;

import com.softlayer.api.http.HttpCredentials;

/** Common interface for all API clients. {@link RestApiClient} is the preferred implementation */
public interface ApiClient {

Expand All @@ -9,7 +11,28 @@ public interface ApiClient {
* @return This instance
*/
ApiClient withCredentials(String username, String apiKey);


/**
* Uses a HTTP Bearer token for authentication instead of API key.
*
* @return This instance
*/
ApiClient withBearerToken(String token);

/**
* Enables logging for client API calls
*
* @return This instance
*/
ApiClient withLoggingEnabled();

/**
* Returns the HTTP Authorization header
*
* @return This instance
*/
HttpCredentials getCredentials();

/**
* Get a service for the given sets of classes and optional ID. It is not recommended to call this
* directly, but rather invoke the service method on the type class.
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/com/softlayer/api/RestApiClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

import com.softlayer.api.annotation.ApiMethod;
import com.softlayer.api.annotation.ApiService;
import com.softlayer.api.http.HttpCredentials;
import com.softlayer.api.http.HttpBasicAuthCredentials;
import com.softlayer.api.http.HttpBearerCredentials;
import com.softlayer.api.http.HttpClient;
import com.softlayer.api.http.HttpClientFactory;
import com.softlayer.api.http.HttpResponse;
Expand Down Expand Up @@ -64,7 +66,7 @@ public class RestApiClient implements ApiClient {
private HttpClientFactory httpClientFactory;
private JsonMarshallerFactory jsonMarshallerFactory;
private boolean loggingEnabled = false;
private HttpBasicAuthCredentials credentials;
private HttpCredentials credentials;

/**
* Create a Rest client that uses the publically available API.
Expand Down Expand Up @@ -114,6 +116,7 @@ public void setLoggingEnabled(boolean loggingEnabled) {
this.loggingEnabled = loggingEnabled;
}

@Override
public RestApiClient withLoggingEnabled() {
this.loggingEnabled = true;
return this;
Expand Down Expand Up @@ -141,7 +144,14 @@ public RestApiClient withCredentials(String username, String apiKey) {
return this;
}

public HttpBasicAuthCredentials getCredentials() {
@Override
public RestApiClient withBearerToken(String token) {
credentials = new HttpBearerCredentials(token);
return this;
}

@Override
public HttpCredentials getCredentials() {
return credentials;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public void setThreadPool(ExecutorService threadPool) {

class BuiltInHttpClient implements HttpClient, HttpResponse {

final HttpBasicAuthCredentials credentials;
final HttpCredentials credentials;
final String method;
final String fullUrl;
final Map<String, List<String>> headers;
Expand All @@ -101,11 +101,7 @@ public BuiltInHttpClient(
String fullUrl,
Map<String, List<String>> headers
) {
// We only support basic auth
if (credentials != null && !(credentials instanceof HttpBasicAuthCredentials)) {
throw new UnsupportedOperationException("Only basic auth is supported, not " + credentials.getClass());
}
this.credentials = (HttpBasicAuthCredentials) credentials;
this.credentials = credentials;
this.method = method;
this.fullUrl = fullUrl;
this.headers = headers;
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/com/softlayer/api/http/HttpBearerCredentials.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.softlayer.api.http;

/** HTTP Bearer authorization support for IBM IAM Tokens.
*
* @see <a href="https://cloud.ibm.com/apidocs/iam-identity-token-api">IAM Tokens</a>
* @see <a href="https://sldn.softlayer.com/article/authenticating-softlayer-api/">Authenticating SoftLayer API</a>
*/
public class HttpBearerCredentials implements HttpCredentials {

protected final String token;

public HttpBearerCredentials(String token) {
this.token = token;
}

/**
* Formats the token into a HTTP Authorization header.
*
* @return String
*/
public String getHeader() {
return "Bearer " + token;
}
}
1 change: 1 addition & 0 deletions src/main/java/com/softlayer/api/http/HttpCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

/** Base interface for all accepted HTTP credentials */
public interface HttpCredentials {
String getHeader();
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,6 @@

public class BuiltInHttpClientFactoryTest {

@Test
public void testGetHttpClientWithoutBasicAuth() {
try {
new BuiltInHttpClientFactory().getHttpClient(
new HttpCredentials() { },
"GET",
"http://example.com",
Collections.emptyMap()
);
fail();
} catch (UnsupportedOperationException e) {
assertTrue(e.getMessage().contains("basic auth"));
}
}

@Test
public void testGetThreadPoolDefaultsToDaemonThreads() throws Exception {
boolean daemon = new BuiltInHttpClientFactory().getThreadPool().submit(
Expand All @@ -38,6 +23,14 @@ public void testGetThreadPoolDefaultsToDaemonThreads() throws Exception {
assertTrue(daemon);
}

@Test
public void testGetThreadPoolLazyLoading() {
BuiltInHttpClientFactory factory = new BuiltInHttpClientFactory();
ExecutorService threadPool = factory.getThreadPool();
assertNotNull(threadPool);
assertEquals(threadPool, factory.getThreadPool());
}

@Test
public void testSetThreadPoolShutsDownNonUserDefined() {
BuiltInHttpClientFactory factory = new BuiltInHttpClientFactory();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.softlayer.api.http;

import static org.junit.Assert.*;

import org.junit.Test;

public class HttpBearerCredentialsTest {

public final String bearerToken = "qqqqwwwweeerrttyyuuiiooppasddfgfgjghjkjklZXxcvcvbvbnnbm";
@Test
public void testConstructor() {
HttpBearerCredentials authCredentials = new HttpBearerCredentials(bearerToken);
assertEquals(bearerToken, authCredentials.token);
}

@Test
public void testGetHeader() {
HttpBearerCredentials authCredentials = new HttpBearerCredentials(bearerToken);
String header = "Bearer " + bearerToken;
assertEquals(header, authCredentials.getHeader());
}
}