Skip to content

Commit 053ac27

Browse files
authored
Merge pull request #9 from helioauth/feature/delete-application-api-key
feat: add API key deletion functionality for applications
2 parents 6092106 + 31b5bd7 commit 053ac27

4 files changed

Lines changed: 88 additions & 5 deletions

File tree

docs/openapi/paths/admin_v1_apps_id_api-key.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,26 @@ get:
2424
description: Not Found
2525
security:
2626
- admin-api: []
27+
28+
delete:
29+
tags:
30+
- Applications
31+
summary: Delete an application's API key
32+
description: Deletes the API key for a specific application by its ID.
33+
operationId: deleteApiKey
34+
parameters:
35+
- name: id
36+
in: path
37+
required: true
38+
schema:
39+
type: string
40+
format: uuid
41+
responses:
42+
'204':
43+
description: No Content
44+
'401':
45+
description: Unauthorized
46+
'404':
47+
description: Not Found
48+
security:
49+
- admin-api: []

src/main/java/com/helioauth/passkeys/api/controller/ClientApplicationController.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@
2222
import com.helioauth.passkeys.api.generated.models.ApplicationApiKey;
2323
import com.helioauth.passkeys.api.generated.models.EditApplicationRequest;
2424
import com.helioauth.passkeys.api.service.ClientApplicationService;
25-
26-
import jakarta.validation.Valid;
2725
import lombok.RequiredArgsConstructor;
2826
import lombok.val;
2927
import org.springframework.http.ResponseEntity;
3028
import org.springframework.web.bind.annotation.PathVariable;
3129
import org.springframework.web.bind.annotation.RequestBody;
3230
import org.springframework.web.bind.annotation.RestController;
3331

32+
import jakarta.validation.Valid;
3433
import java.net.URI;
3534
import java.util.List;
3635
import java.util.UUID;
@@ -80,4 +79,9 @@ public ResponseEntity<Void> delete(@PathVariable UUID id) {
8079

8180
return deleted ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build();
8281
}
83-
}
82+
83+
public ResponseEntity<Void> deleteApiKey(@PathVariable UUID id) {
84+
boolean deleted = clientApplicationService.deleteApiKey(id);
85+
return deleted ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build();
86+
}
87+
}

src/main/java/com/helioauth/passkeys/api/service/ClientApplicationService.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.helioauth.passkeys.api.service;
1818

19-
import com.helioauth.passkeys.api.domain.ClientApplication;
2019
import com.helioauth.passkeys.api.domain.ClientApplicationRepository;
2120
import com.helioauth.passkeys.api.generated.models.AddApplicationRequest;
2221
import com.helioauth.passkeys.api.generated.models.Application;
@@ -89,6 +88,17 @@ public boolean delete(UUID id) {
8988
return false;
9089
}
9190

91+
@Transactional
92+
public boolean deleteApiKey(UUID id) {
93+
return repository.findById(id)
94+
.map(application -> {
95+
application.setApiKey(null);
96+
repository.save(application);
97+
return true;
98+
})
99+
.orElse(false);
100+
}
101+
92102
private String generateApiKey() {
93103
byte[] buffer = new byte[16];
94104
random.nextBytes(buffer);

src/test/java/com/helioauth/passkeys/api/service/ClientApplicationServiceTest.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@
4040
import static org.junit.jupiter.api.Assertions.assertEquals;
4141
import static org.junit.jupiter.api.Assertions.assertFalse;
4242
import static org.junit.jupiter.api.Assertions.assertNotNull;
43+
import static org.junit.jupiter.api.Assertions.assertNull;
4344
import static org.junit.jupiter.api.Assertions.assertTrue;
4445
import static org.mockito.ArgumentMatchers.any;
46+
import static org.mockito.Mockito.never;
47+
import static org.mockito.Mockito.times;
4548
import static org.mockito.Mockito.verify;
4649
import static org.mockito.Mockito.when;
4750

@@ -197,4 +200,47 @@ public void getClientApplicationApiKeyTest() {
197200
assertTrue(result.isPresent());
198201
assertEquals(apiKey, result.get().getApiKey());
199202
}
200-
}
203+
204+
@Test
205+
public void testDeleteApiKey_success() {
206+
// Setup
207+
UUID appId = UUID.randomUUID();
208+
ClientApplication application = ClientApplication.builder()
209+
.id(appId)
210+
.name("Test App")
211+
.apiKey("someapikey")
212+
.relyingPartyHostname("localhost")
213+
.createdAt(Instant.now())
214+
.updatedAt(Instant.now())
215+
.build();
216+
217+
when(repository.findById(appId)).thenReturn(Optional.of(application));
218+
// Mock repository.save to return the application object after modifying it in the service
219+
when(repository.save(any(ClientApplication.class))).thenReturn(application);
220+
221+
// Execute
222+
boolean result = service.deleteApiKey(appId);
223+
224+
// Validate
225+
assertTrue(result);
226+
assertNull(application.getApiKey()); // Verify the API key was set to null
227+
verify(repository, times(1)).findById(appId);
228+
verify(repository, times(1)).save(application); // Verify save was called with the modified object
229+
}
230+
231+
@Test
232+
public void testDeleteApiKey_notFound() {
233+
// Setup
234+
UUID appId = UUID.randomUUID();
235+
236+
when(repository.findById(appId)).thenReturn(Optional.empty());
237+
238+
// Execute
239+
boolean result = service.deleteApiKey(appId);
240+
241+
// Validate
242+
assertFalse(result);
243+
verify(repository, times(1)).findById(appId);
244+
verify(repository, never()).save(any(ClientApplication.class)); // Verify save was not called
245+
}
246+
}

0 commit comments

Comments
 (0)