initial commit

This commit is contained in:
allard
2025-11-23 18:58:51 +01:00
commit 376a944abc
1553 changed files with 314731 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
<?xml version='1.0' encoding='utf-8'?>
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ibm.codey.bank</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.ibm.codey.bank</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<!-- Open Liberty Features -->
<dependency>
<groupId>io.openliberty.features</groupId>
<artifactId>microProfile-3.0</artifactId>
<type>esa</type>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,26 @@
package com.ibm.codey.bank;
import javax.inject.Inject;
import org.eclipse.microprofile.jwt.Claim;
import org.eclipse.microprofile.jwt.Claims;
public class BaseResource {
@Inject
@Claim("sub")
private String subject;
@Inject
@Claim(standard = Claims.raw_token)
private String rawToken;
protected String getCallerSubject() {
return subject;
}
protected String getCallerCredentials() {
return "Bearer " + rawToken;
}
}

View File

@@ -0,0 +1,15 @@
package com.ibm.codey.bank.accounts.json;
import javax.json.bind.annotation.JsonbProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter @Setter @ToString
public class UserRegistration {
@JsonbProperty
private boolean consentGiven;
}

View File

@@ -0,0 +1,18 @@
package com.ibm.codey.bank.accounts.json;
import javax.json.bind.annotation.JsonbProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter @Setter @ToString
public class UserRegistrationInfo {
@JsonbProperty
private String userId;
@JsonbProperty
private boolean consentGiven;
}

View File

@@ -0,0 +1,23 @@
package com.ibm.codey.bank.catalog;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletionStage;
import javax.enterprise.context.Dependent;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@Dependent
@RegisterRestClient
public interface KnativeService {
@POST
@Path("process")
public CompletionStage<String> processTransaction(@QueryParam("transactionId") String transactionId, @QueryParam("category") String category, @QueryParam("amount") String amount);
}

View File

@@ -0,0 +1,30 @@
package com.ibm.codey.bank.catalog;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.Dependent;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import com.ibm.codey.bank.accounts.json.UserRegistration;
import com.ibm.codey.bank.accounts.json.UserRegistrationInfo;
@Dependent
@RegisterRestClient
public interface UserService {
@GET
@Path("self")
@Produces(MediaType.APPLICATION_JSON)
public UserRegistrationInfo getUserConsent(@HeaderParam("Authorization") String authorizationHeader);
}

View File

@@ -0,0 +1,23 @@
package com.ibm.codey.bank.catalog.json;
import java.math.BigDecimal;
import javax.json.bind.annotation.JsonbProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter @Setter @ToString
public class CreateTransactionDefinition {
@JsonbProperty
private String transactionName;
@JsonbProperty
private String category;
@JsonbProperty
private BigDecimal amount;
}

View File

@@ -0,0 +1,17 @@
package com.ibm.codey.bank.catalog.json;
import java.math.BigDecimal;
import javax.json.bind.annotation.JsonbProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter @Setter @ToString
public class RewardTransactionDefinition {
@JsonbProperty
private BigDecimal pointsEarned;
}

View File

@@ -0,0 +1,66 @@
package com.ibm.codey.bank.interceptor;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.json.Json;
import javax.json.JsonObjectBuilder;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.jwt.Claim;
/*
* This interceptor is used with the JAXRS resource classes to log any exception and return a 500 status code to the client.
* This could have been accomplished with an ExceptionMapper as well but an interceptor lets us also log information about
* the failing method and input parameters.
*/
public class LoggingInterceptor {
private static final Logger log = Logger.getLogger(LoggingInterceptor.class.getName());
@Inject
@Claim("sub")
private String subject;
@AroundInvoke
public Object logInvocation(InvocationContext ctx) {
try {
Object result = ctx.proceed();
logRequestAndResult(ctx, result);
return result;
} catch(Throwable e) {
String clz = ctx.getMethod().getDeclaringClass().getName();
String method = ctx.getMethod().getName();
Object[] params = ctx.getParameters();
if (params != null && params.length > 0) {
log.log(Level.SEVERE, "***** Exception in " + clz + "." + method, params);
} else {
log.log(Level.SEVERE, "***** Exception in " + clz + "." + method);
}
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
private void logRequestAndResult(InvocationContext ctx, Object result) {
String methodName = ctx.getMethod().getName();
Object[] params = ctx.getParameters();
JsonObjectBuilder requestBuilder = Json.createObjectBuilder()
.add("subject", subject)
.add("action", methodName);
if (params != null && params.length > 0) {
requestBuilder.add("input", Arrays.toString(params));
}
if (result instanceof Response) {
Response response = (Response)result;
requestBuilder.add("statuscode", response.getStatus());
}
log.log(Level.INFO, "API REQUEST", requestBuilder.build());
}
}

View File

@@ -0,0 +1,38 @@
package com.ibm.codey.bank.interceptor;
import javax.annotation.Priority;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.jwt.Claim;
import com.ibm.codey.bank.interceptor.binding.RequiresAuthorization;
/*
* This interceptor is used with the JAXRS resource classes to enforce a client scope for authorization purposes.
*/
@RequiresAuthorization @Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class SecurityInterceptor {
@Inject
@Claim("scope")
private String scope;
@AroundInvoke
public Object checkScope(InvocationContext ctx) throws Exception {
String[] scopeList = scope.split(" ");
for(String hasScope : scopeList) {
if (hasScope.equals("admin")) {
Object result = ctx.proceed();
return result;
}
}
return Response.status(Response.Status.FORBIDDEN).entity("admin permission required").build();
}
}

View File

@@ -0,0 +1,18 @@
package com.ibm.codey.bank.interceptor.binding;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;
@Inherited
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface RequiresAuthorization {
}