Skip to content

Commit 21958a3

Browse files
authored
Merge pull request #1394 from utmstack/backlog/api_key
Backlog/api key
2 parents 164c851 + a3ba51a commit 21958a3

43 files changed

Lines changed: 2044 additions & 29 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ local.properties
6262
*.orig
6363
classes/
6464
out/
65+
.nvim/
6566

6667
######################
6768
# Visual Studio Code

backend/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,12 @@
376376
<version>3.0.5</version>
377377
</dependency>
378378

379+
<dependency>
380+
<groupId>commons-net</groupId>
381+
<artifactId>commons-net</artifactId>
382+
<version>3.9.0</version>
383+
</dependency>
384+
379385
</dependencies>
380386

381387
<build>

backend/src/main/java/com/park/utmstack/advice/GlobalExceptionHandler.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
import com.park.utmstack.security.TooMuchLoginAttemptsException;
55
import com.park.utmstack.service.application_events.ApplicationEventService;
66
import com.park.utmstack.util.ResponseUtil;
7-
import com.park.utmstack.util.exceptions.IncidentAlertConflictException;
8-
import com.park.utmstack.util.exceptions.NoAlertsProvidedException;
9-
import com.park.utmstack.util.exceptions.TfaVerificationException;
10-
import com.park.utmstack.util.exceptions.TooManyRequestsException;
7+
import com.park.utmstack.util.exceptions.*;
118
import lombok.RequiredArgsConstructor;
129
import lombok.extern.slf4j.Slf4j;
1310
import org.springframework.http.HttpStatus;
@@ -41,8 +38,9 @@ public ResponseEntity<?> handleTooManyLoginAttempts(TooMuchLoginAttemptsExceptio
4138
return ResponseUtil.buildLockedResponse(e.getMessage());
4239
}
4340

44-
@ExceptionHandler(NoSuchElementException.class)
45-
public ResponseEntity<?> handleNotFound(NoSuchElementException e, HttpServletRequest request) {
41+
@ExceptionHandler({NoSuchElementException.class,
42+
ApiKeyNotFoundException.class})
43+
public ResponseEntity<?> handleNotFound(Exception e, HttpServletRequest request) {
4644
return ResponseUtil.buildNotFoundResponse(e.getMessage());
4745
}
4846

@@ -56,8 +54,9 @@ public ResponseEntity<?> handleNoAlertsProvided(Exception e, HttpServletRequest
5654
return ResponseUtil.buildErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage());
5755
}
5856

59-
@ExceptionHandler(IncidentAlertConflictException.class)
60-
public ResponseEntity<?> handleConflict(IncidentAlertConflictException e, HttpServletRequest request) {
57+
@ExceptionHandler({IncidentAlertConflictException.class,
58+
ApiKeyExistException.class})
59+
public ResponseEntity<?> handleConflict(Exception e, HttpServletRequest request) {
6160
return ResponseUtil.buildErrorResponse(HttpStatus.CONFLICT, e.getMessage());
6261
}
6362

backend/src/main/java/com/park/utmstack/config/Constants.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import com.park.utmstack.domain.index_pattern.enums.SystemIndexPattern;
44

5+
import java.util.Collections;
56
import java.util.HashMap;
7+
import java.util.List;
68
import java.util.Map;
79

810
public final class Constants {
@@ -137,6 +139,7 @@ public final class Constants {
137139
// Defines the index pattern for querying Elasticsearch statistics indexes.
138140
// ----------------------------------------------------------------------------------
139141
public static final String STATISTICS_INDEX_PATTERN = "v11-statistics-*";
142+
public static final String V11_API_ACCESS_LOGS = "v11-api-access-logs-*";
140143

141144
// Logging
142145
public static final String TRACE_ID_KEY = "traceId";
@@ -156,6 +159,9 @@ public final class Constants {
156159
public static final String CONF_TYPE_PASSWORD = "password";
157160
public static final String CONF_TYPE_FILE = "file";
158161

162+
public static final String API_KEY_HEADER = "Utm-Api-Key";
163+
public static final List<String> API_ENDPOINT_IGNORE = Collections.emptyList();
164+
159165
private Constants() {
160166
}
161167
}

backend/src/main/java/com/park/utmstack/config/OpenApiConfiguration.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,30 @@ public OpenApiConfiguration(InfoEndpoint infoEndpoint) {
2323
@Bean
2424
public OpenAPI customOpenAPI() {
2525
final String securitySchemeBearer = "bearerAuth";
26+
final String securitySchemeApiInternalKey = "ApiInternalKeyAuth";
2627
final String securitySchemeApiKey = "ApiKeyAuth";
28+
2729
final String apiTitle = "UTMStack API";
2830
String version = MapUtil.flattenToStringMap(infoEndpoint.info(), true).get("build.version");
2931
return new OpenAPI()
30-
.addSecurityItem(new SecurityRequirement().addList(securitySchemeBearer).addList(securitySchemeApiKey))
32+
.addSecurityItem(new SecurityRequirement()
33+
.addList(securitySchemeBearer)
34+
.addList(securitySchemeApiInternalKey)
35+
.addList(securitySchemeApiKey))
3136
.components(new Components()
3237
.addSecuritySchemes(securitySchemeBearer,
3338
new SecurityScheme()
3439
.name(securitySchemeBearer)
3540
.type(SecurityScheme.Type.HTTP)
3641
.scheme("bearer")
3742
.bearerFormat("JWT"))
38-
.addSecuritySchemes(securitySchemeApiKey, new SecurityScheme()
43+
.addSecuritySchemes(securitySchemeApiInternalKey, new SecurityScheme()
3944
.name("Utm-Internal-Key")
4045
.type(SecurityScheme.Type.APIKEY)
46+
.in(SecurityScheme.In.HEADER))
47+
.addSecuritySchemes(securitySchemeApiKey, new SecurityScheme()
48+
.name(Constants.API_KEY_HEADER)
49+
.type(SecurityScheme.Type.APIKEY)
4150
.in(SecurityScheme.In.HEADER)))
4251
.info(new Info().title(apiTitle).version(version))
4352
.addServersItem(new Server().url("/").description("Default Server URL"));

backend/src/main/java/com/park/utmstack/config/SecurityConfiguration.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
package com.park.utmstack.config;
22

3+
import com.park.utmstack.loggin.api_key.ApiKeyUsageLoggingService;
34
import com.park.utmstack.loggin.filter.MdcCleanupFilter;
5+
import com.park.utmstack.repository.UserRepository;
46
import com.park.utmstack.security.AuthoritiesConstants;
7+
import com.park.utmstack.security.api_key.ApiKeyConfigurer;
8+
import com.park.utmstack.security.api_key.ApiKeyFilter;
59
import com.park.utmstack.security.internalApiKey.InternalApiKeyConfigurer;
610
import com.park.utmstack.security.internalApiKey.InternalApiKeyProvider;
711
import com.park.utmstack.security.jwt.JWTConfigurer;
12+
import com.park.utmstack.security.jwt.JWTFilter;
813
import com.park.utmstack.security.jwt.TokenProvider;
14+
import com.park.utmstack.service.api_key.ApiKeyService;
15+
import lombok.RequiredArgsConstructor;
16+
import org.apache.commons.net.util.SubnetUtils;
917
import org.springframework.beans.factory.BeanInitializationException;
1018
import org.springframework.boot.web.servlet.FilterRegistrationBean;
1119
import org.springframework.context.annotation.Bean;
@@ -29,8 +37,11 @@
2937

3038
import javax.annotation.PostConstruct;
3139
import javax.servlet.http.HttpServletResponse;
40+
import java.util.concurrent.ConcurrentHashMap;
41+
import java.util.concurrent.ConcurrentMap;
3242

3343
@Configuration
44+
@RequiredArgsConstructor
3445
@EnableWebSecurity
3546
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
3647
@Import(SecurityProblemSupport.class)
@@ -41,17 +52,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
4152
private final TokenProvider tokenProvider;
4253
private final CorsFilter corsFilter;
4354
private final InternalApiKeyProvider internalApiKeyProvider;
44-
45-
public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder,
46-
UserDetailsService userDetailsService,
47-
TokenProvider tokenProvider,
48-
CorsFilter corsFilter, InternalApiKeyProvider internalApiKeyProvider) {
49-
this.authenticationManagerBuilder = authenticationManagerBuilder;
50-
this.userDetailsService = userDetailsService;
51-
this.tokenProvider = tokenProvider;
52-
this.corsFilter = corsFilter;
53-
this.internalApiKeyProvider = internalApiKeyProvider;
54-
}
55+
private final ApiKeyFilter apiKeyFilter;
5556

5657
@PostConstruct
5758
public void init() {
@@ -127,7 +128,10 @@ public void configure(HttpSecurity http) throws Exception {
127128
.and()
128129
.apply(securityConfigurerAdapterForJwt())
129130
.and()
130-
.apply(securityConfigurerAdapterForInternalApiKey());
131+
.apply(securityConfigurerAdapterForInternalApiKey())
132+
.and()
133+
.apply(securityConfigurerAdapterForApiKey()) ;
134+
131135

132136
}
133137

@@ -138,4 +142,9 @@ private JWTConfigurer securityConfigurerAdapterForJwt() {
138142
private InternalApiKeyConfigurer securityConfigurerAdapterForInternalApiKey() {
139143
return new InternalApiKeyConfigurer(internalApiKeyProvider);
140144
}
145+
146+
private ApiKeyConfigurer securityConfigurerAdapterForApiKey() {
147+
return new ApiKeyConfigurer(apiKeyFilter);
148+
}
149+
141150
}

backend/src/main/java/com/park/utmstack/domain/User.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public class User extends AbstractAuditingEntity implements Serializable {
9797
private Boolean defaultPassword;
9898

9999
@JsonIgnore
100-
@ManyToMany
100+
@ManyToMany(fetch = FetchType.EAGER)
101101
@JoinTable(name = "jhi_user_authority", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")}, inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "name")})
102102

103103
@BatchSize(size = 20)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.park.utmstack.domain.api_keys;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
import javax.persistence.*;
9+
import java.io.Serializable;
10+
import java.time.Instant;
11+
import java.util.UUID;
12+
13+
@Data
14+
@Builder
15+
@NoArgsConstructor
16+
@AllArgsConstructor
17+
@Entity
18+
@Table(name = "api_keys")
19+
public class ApiKey implements Serializable {
20+
21+
@Id
22+
@GeneratedValue(strategy = GenerationType.IDENTITY)
23+
private Long id;
24+
25+
@Column(nullable = false)
26+
private Long userId;
27+
28+
@Column(nullable = false)
29+
private String name;
30+
31+
@Column(nullable = false)
32+
private String apiKey;
33+
34+
@Column
35+
private String allowedIp;
36+
37+
@Column(nullable = false)
38+
private Instant createdAt;
39+
40+
private Instant generatedAt;
41+
42+
@Column
43+
private Instant expiresAt;
44+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.park.utmstack.domain.api_keys;
2+
3+
import com.park.utmstack.service.dto.auditable.AuditableDTO;
4+
import lombok.*;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
9+
@Builder
10+
@Getter
11+
@Setter
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
public class ApiKeyUsageLog implements AuditableDTO {
15+
16+
private String id;
17+
private String apiKeyId;
18+
private String apiKeyName;
19+
private String userId;
20+
private String timestamp;
21+
private String endpoint;
22+
private String address;
23+
private String errorMessage;
24+
private String queryParams;
25+
private String payload;
26+
private String userAgent;
27+
private String httpMethod;
28+
private String statusCode;
29+
30+
@Override
31+
public Map<String, Object> toAuditMap() {
32+
Map<String, Object> map = new HashMap<>();
33+
34+
map.put("id", id);
35+
map.put("api_key_id", apiKeyId);
36+
map.put("api_key_name", apiKeyName);
37+
map.put("user_id", userId);
38+
map.put("timestamp", timestamp != null ? timestamp : null);
39+
map.put("endpoint", endpoint);
40+
map.put("address", address);
41+
map.put("error_message", errorMessage);
42+
map.put("query_params", queryParams);
43+
map.put("user_agent", userAgent);
44+
map.put("http_method", httpMethod);
45+
map.put("status_code", statusCode);
46+
47+
return map;
48+
}
49+
}

backend/src/main/java/com/park/utmstack/domain/application_events/enums/ApplicationEventType.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,9 @@ public enum ApplicationEventType {
4242
ERROR,
4343
WARNING,
4444
INFO,
45-
MODULE_ACTIVATION_ATTEMPT, MODULE_ACTIVATION_SUCCESS, UNDEFINED
45+
MODULE_ACTIVATION_ATTEMPT,
46+
MODULE_ACTIVATION_SUCCESS,
47+
API_KEY_ACCESS_SUCCESS,
48+
API_KEY_ACCESS_FAILURE,
49+
UNDEFINED
4650
}

0 commit comments

Comments
 (0)