Skip to content

Commit de5f0c7

Browse files
committed
MPDO:1015 code refactoring
1 parent f80a821 commit de5f0c7

File tree

7 files changed

+279
-146
lines changed

7 files changed

+279
-146
lines changed
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
schema_version: 20180708
22
name: basicauth
3-
version: 0.0.6
3+
version: 0.0.21
44
runtime: java
55
build_image: fnproject/fn-java-fdk-build:jdk11-1.0.146
66
run_image: fnproject/fn-java-fdk:jre11-1.0.146
77
cmd: com.example.fn.BasicAuth::handleRequest
8+
memory: 512
9+
timeout: 120

samples/oci-apigw-idcs-auth-basic/pom.xml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
53
<modelVersion>4.0.0</modelVersion>
64
<properties>
75
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
86
<fdk.version>1.0.146</fdk.version>
7+
<jdk.version>11</jdk.version>
98
</properties>
9+
1010
<groupId>com.example.fn</groupId>
1111
<artifactId>basicAuth</artifactId>
12-
<version>1.0.0</version>
12+
<version>1.0.1</version>
1313

1414
<dependencies>
1515
<dependency>
@@ -49,18 +49,18 @@
4949
<artifactId>maven-compiler-plugin</artifactId>
5050
<version>3.3</version>
5151
<configuration>
52-
<source>11</source>
53-
<target>11</target>
52+
<source>${jdk.version}</source>
53+
<target>${jdk.version}</target>
5454
</configuration>
5555
</plugin>
5656
<plugin>
57-
<groupId>org.apache.maven.plugins</groupId>
58-
<artifactId>maven-surefire-plugin</artifactId>
59-
<version>2.22.1</version>
60-
<configuration>
61-
<useSystemClassLoader>false</useSystemClassLoader>
62-
</configuration>
57+
<groupId>org.apache.maven.plugins</groupId>
58+
<artifactId>maven-surefire-plugin</artifactId>
59+
<version>2.22.1</version>
60+
<configuration>
61+
<useSystemClassLoader>false</useSystemClassLoader>
62+
</configuration>
6363
</plugin>
6464
</plugins>
6565
</build>
66-
</project>
66+
</project>
Lines changed: 112 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,153 @@
11
package com.example.fn;
22

3-
import java.net.http.HttpClient;
4-
import java.net.http.HttpRequest;
3+
import static com.example.fn.util.ResourceServerConfig.TOKEN_PREFIX;
4+
import static com.example.fn.util.ResourceServerConfig.CONFIG_KEY_IDCS_URL;
5+
import static com.example.fn.util.ResourceServerConfig.CONFIG_KEY_CLIENT_ID;
6+
import static com.example.fn.util.ResourceServerConfig.CONFIG_KEY_CLIENT_SECRET;
7+
import static com.example.fn.util.ResourceServerConfig.CONFIG_KEY_SCOPE_AUD;
8+
import static com.example.fn.util.ResourceServerConfig.DEFAULT_GRANT_TYPE;
9+
import static com.example.fn.util.ResourceServerConfig.TOKEN_CLAIM_KEY_EXPIRY;
10+
import static com.example.fn.util.ResourceServerConfig.TOKEN_CLAIM_KEY_SUBJECT;
11+
import static com.example.fn.util.ResourceServerConfig.TOKEN_CLAIM_KEY_SCOPE;
12+
513
import java.net.http.HttpResponse;
6-
import java.net.URI;
714

815
import java.io.IOException;
916
import java.io.UnsupportedEncodingException;
1017
import java.lang.InterruptedException;
1118
import org.json.JSONObject;
12-
import java.util.*;
1319

14-
public class BasicAuth {
15-
public static class Input {
16-
public String type;
17-
public String token;
18-
}
20+
import com.example.fn.util.Helper;
21+
import com.fnproject.fn.api.FnConfiguration;
22+
import com.fnproject.fn.api.RuntimeContext;
1923

20-
public static class Result {
21-
public boolean active = false;
22-
public String principal;
23-
public String[] scope;
24-
public String expiresAt;
25-
}
24+
import java.util.*;
2625

27-
private static final String TOKEN_PREFIX = "Basic ";
28-
private static final String IDCS_URL = ResourceServerConfig.IDCS_URL;
26+
/**
27+
* Main class implementing the {@code handleRequest} method, takes the user
28+
* credentials as input, authenticates the credentials against the identity
29+
* provider and if the authentication is successful then returns the following
30+
* claims from the access token <br/>
31+
* <ul>
32+
* <li>exp</li>
33+
* <li>sub</li>
34+
* <li>scope</li>
35+
* </ul>
36+
*/
37+
public class BasicAuth {
2938

30-
public String[] getUserDetailsFromToken(String token) {
31-
String data = token.substring(TOKEN_PREFIX.length());
32-
String[] user = new String(Base64.getDecoder().decode(data)).split(":", 2);
33-
return user;
39+
private static String IDCS_URL = null;
40+
private static String CLIENT_ID = null;
41+
private static String CLIENT_SECRET = null;
42+
private static String SCOPE_AUD = null;
43+
44+
/**
45+
* Reads the configuration parameters and sets the respective variables during
46+
* function initialization.
47+
*
48+
* @param {@link RuntimeContext} ctx
49+
*/
50+
@FnConfiguration
51+
public void config(final RuntimeContext ctx) {
52+
IDCS_URL = ctx.getConfigurationByKey(CONFIG_KEY_IDCS_URL).orElse(null);
53+
CLIENT_ID = ctx.getConfigurationByKey(CONFIG_KEY_CLIENT_ID).orElse(null);
54+
CLIENT_SECRET = ctx.getConfigurationByKey(CONFIG_KEY_CLIENT_SECRET).orElse(null);
55+
SCOPE_AUD = ctx.getConfigurationByKey(CONFIG_KEY_SCOPE_AUD).orElse(null);
3456
}
3557

36-
public Result handleRequest(Input input) throws UnsupportedEncodingException, InterruptedException {
37-
Result returnValue = new Result();
58+
/**
59+
* Entry point of the function
60+
*
61+
* @param {@link Input} input
62+
* @return {@link Result}
63+
* @throws UnsupportedEncodingException
64+
* @throws InterruptedException
65+
*/
66+
public Result handleRequest(final Input input) throws UnsupportedEncodingException, InterruptedException {
67+
final Result returnValue = new Result();
68+
69+
if (!isConfigValid()) {
70+
returnValue.active = false;
71+
System.out.println(
72+
"Function initialization error, all config parameters not set, please ensure that following config variables are set IDCS_URL, CLIENT_ID, CLIENT_SECRET");
73+
return returnValue;
74+
}
3875

3976
if (input.token == null || !input.token.startsWith(TOKEN_PREFIX)) {
4077
returnValue.active = false;
4178
System.out.println("Request error, missing credentials");
4279
return returnValue;
4380
}
4481

45-
String[] user = getUserDetailsFromToken(input.token);
82+
final String[] user = getUserDetailsFromToken(input.token);
4683
if (user.length != 2 || user[0] == null || user[0].isEmpty() || user[1] == null || user[1].isEmpty()) {
84+
returnValue.active = false;
4785
System.out.println("Request error username or password missing");
4886
return returnValue;
4987
}
5088

51-
String username = user[0];
52-
String password = user[1];
53-
String clientId = ResourceServerConfig.CLIENT_ID;
54-
String clientSecret = ResourceServerConfig.CLIENT_SECRET;
55-
String authzHdrVal = clientId + ":" + clientSecret;
56-
String idcsScope = ResourceServerConfig.SCOPE_AUD;
57-
58-
String reqBody = "grant_type=password" +
59-
"&username=" + username +
60-
"&password=" + password +
61-
"&scope=" + idcsScope;
89+
final String authzHdrVal = CLIENT_ID + ":" + CLIENT_SECRET;
90+
final String reqBody = Helper.createRequestBody(user[0], user[1], SCOPE_AUD, DEFAULT_GRANT_TYPE);
6291

6392
try {
64-
HttpClient client = HttpClient.newHttpClient();
65-
66-
HttpRequest request = HttpRequest.newBuilder()
67-
.uri(URI.create(IDCS_URL))
68-
.header("Content-Type", "application/x-www-form-urlencoded")
69-
.header("Authorization", "Basic " + Base64.getEncoder().encodeToString(authzHdrVal.getBytes("UTF-8")))
70-
.POST(HttpRequest.BodyPublishers.ofString(reqBody))
71-
.build();
72-
73-
HttpResponse<String> response = client.send( request,
74-
HttpResponse.BodyHandlers.ofString() );
75-
93+
final HttpResponse<String> response = Helper.callIDCS(IDCS_URL, authzHdrVal, reqBody);
7694

7795
if (response.statusCode() == 200) {
96+
final String responseString = (String) response.body();
97+
final JSONObject payload = Helper.getTokenBody(responseString);
7898

79-
String responseString = (String) response.body();
80-
String[] chunks = responseString.split("\\.");
81-
String respjson = new String(Base64.getUrlDecoder().decode(chunks[1]));
82-
JSONObject payload = new JSONObject(respjson);
83-
Date expTime = new Date(payload.getLong("exp")*1000);
84-
85-
returnValue.principal = payload.getString("sub");
86-
returnValue.scope = payload.getString("scope").split(" ");
99+
final Date expTime = new Date(payload.getLong(TOKEN_CLAIM_KEY_EXPIRY) * 1000);
100+
returnValue.principal = payload.getString(TOKEN_CLAIM_KEY_SUBJECT);
101+
returnValue.scope = payload.getString(TOKEN_CLAIM_KEY_SCOPE).split(" ");
87102
returnValue.expiresAt = expTime.toString();
88103
returnValue.active = true;
104+
89105
System.out.println("Authentication successful");
90106
}
91107
} catch (IOException e) {
92108
e.printStackTrace();
93109
}
94110
return returnValue;
95111
}
112+
113+
/**
114+
* Returns true if all the configuration variables are set else returns false
115+
*
116+
* @return
117+
*/
118+
private boolean isConfigValid() {
119+
if (IDCS_URL != null && !IDCS_URL.trim().isEmpty()
120+
&& CLIENT_ID != null && !CLIENT_ID.trim().isEmpty()
121+
&& CLIENT_SECRET != null && !CLIENT_SECRET.isEmpty()
122+
&& SCOPE_AUD != null && !SCOPE_AUD.trim().isEmpty()) {
123+
return true;
124+
}
125+
return false;
126+
}
127+
128+
/**
129+
* The input contains the username and password in {@link Base64} encoded
130+
* format. The format of the token is Base64 encoded <username>:<password>. This
131+
* function decodes the token and returns the username and password.
132+
*
133+
* @param {@link String} token
134+
* @return {@link String} array with username and password
135+
*/
136+
private String[] getUserDetailsFromToken(final String token) {
137+
final String data = token.substring(TOKEN_PREFIX.length());
138+
final String[] user = new String(Base64.getDecoder().decode(data)).split(":", 2);
139+
return user;
140+
}
141+
142+
public static class Input {
143+
public String type;
144+
public String token;
145+
}
146+
147+
public static class Result {
148+
public boolean active = false;
149+
public String principal;
150+
public String[] scope;
151+
public String expiresAt;
152+
}
96153
}

samples/oci-apigw-idcs-auth-basic/src/main/java/com/example/fn/ResourceServerConfig.java

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.example.fn.util;
2+
3+
import static com.example.fn.util.ResourceServerConfig.TOKEN_PREFIX;
4+
import static com.example.fn.util.ResourceServerConfig.HEADER_NAME_CONTENT_TYPE;
5+
import static com.example.fn.util.ResourceServerConfig.HEADER_NAME_AUTHORIZATION;
6+
import static com.example.fn.util.ResourceServerConfig.HEADER_VALUE_CONTENT_TYPE;
7+
8+
import java.io.IOException;
9+
import java.net.URI;
10+
import java.net.http.HttpClient;
11+
import java.net.http.HttpRequest;
12+
import java.net.http.HttpResponse;
13+
import java.util.Base64;
14+
15+
import org.json.JSONObject;
16+
17+
/**
18+
* Util class that contains some common utility methods
19+
*/
20+
public final class Helper {
21+
22+
private Helper() {
23+
//
24+
}
25+
26+
/**
27+
* Creates the POST request body that will be sent to IDCS token endpoint
28+
*
29+
* @param {@link String} username
30+
* @param {@link String} password
31+
* @param {@link String} scope
32+
* @param {@link String} grantType
33+
* @return {@link String} request body
34+
*/
35+
public static String createRequestBody(final String username, final String password, final String scope,
36+
final String grantType) {
37+
return "grant_type=" + grantType +
38+
"&username=" + username +
39+
"&password=" + password +
40+
"&scope=" + scope;
41+
}
42+
43+
/**
44+
*
45+
* Calls IDCS token endpoint to validate the username and password and get the
46+
* access token.
47+
*
48+
* @param {@link String} url
49+
* @param {@link String} authHeader
50+
* @param {@link String} requestBody
51+
* @return {@link HttpResponse}
52+
* @throws InterruptedException
53+
* @throws IOException
54+
*/
55+
public static HttpResponse<String> callIDCS(final String url, final String authHeader, final String requestBody)
56+
throws IOException, InterruptedException {
57+
final HttpClient client = HttpClient.newHttpClient();
58+
59+
final HttpRequest request = HttpRequest.newBuilder()
60+
.uri(URI.create(url))
61+
.header(HEADER_NAME_CONTENT_TYPE, HEADER_VALUE_CONTENT_TYPE)
62+
.header(HEADER_NAME_AUTHORIZATION,
63+
TOKEN_PREFIX + Base64.getEncoder().encodeToString(authHeader.getBytes("UTF-8")))
64+
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
65+
.build();
66+
67+
return client.send(request,
68+
HttpResponse.BodyHandlers.ofString());
69+
}
70+
71+
/**
72+
* Returns the body from the access token. The token is of the JWT format with 3
73+
* parts separated by "." First part is header, body is the second part and the
74+
* last part is signature
75+
*
76+
* @param response
77+
* @return
78+
*/
79+
public static JSONObject getTokenBody(final String response) {
80+
final String[] chunks = response.split("\\.");
81+
final String respjson = new String(Base64.getUrlDecoder().decode(chunks[1]));
82+
return new JSONObject(respjson);
83+
}
84+
}

0 commit comments

Comments
 (0)