Skip to content

Commit

Permalink
Reset client secret
Browse files Browse the repository at this point in the history
  • Loading branch information
Portals committed Sep 6, 2024
1 parent c7e31bf commit 3f8c313
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,14 @@ public ModelAndView getApiKeys(
return mv;
}

private ModelAndView createGetApiKey(boolean htmxRequest, String apiKeyId, @Nullable String token) {
private ModelAndView createGetApiKey(
boolean htmxRequest, String apiKeyId, @Nullable String token) {
if (!isValidUUID(apiKeyId)) {
return createApiKeyNotFound(apiKeyId, htmxRequest);
}

Optional<ApiKeyFacade.ApiKeyDTO> maybeApiKey =
this.apiKeyFacade.getById(UUID.fromString(apiKeyId));
this.apiKeyFacade.getById(UUID.fromString(apiKeyId));

if (maybeApiKey.isEmpty()) {
return createApiKeyNotFound(apiKeyId, htmxRequest);
Expand Down Expand Up @@ -198,8 +199,6 @@ public ModelAndView createApiKey(
@DeleteMapping("/api-keys/{id}")
public ModelAndView deleteApiKey(
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest,
@RequestHeader(value = "return-empty-on-delete", required = false)
boolean returnEmptyOnDelete,
HttpServletResponse response,
@PathVariable("id") UUID id) {
try {
Expand All @@ -208,12 +207,7 @@ public ModelAndView deleteApiKey(
throw new RuntimeException(e);
}

if (returnEmptyOnDelete) {
response.addHeader("HX-Reswap", "delete");
response.addHeader("HX-Retarget", "closest article");
} else {
response.addHeader("HX-Redirect", "/api-keys");
}
response.addHeader("HX-Redirect", "/api-keys");

return new ModelAndView("common/empty");
}
Expand Down Expand Up @@ -292,12 +286,10 @@ public ModelAndView updateSettings(

@PostMapping("/api-keys/{apiKeyId}/reset")
public ModelAndView resetApiKeyToken(
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest,
@PathVariable("apiKeyId") UUID apiKeyId
) {
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest,
@PathVariable("apiKeyId") UUID apiKeyId) {
String newToken = this.apiKeyFacade.resetApiKey(apiKeyId);

return createGetApiKey(htmxRequest, apiKeyId.toString(), newToken);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
import it.chalmers.gamma.app.client.domain.authority.AuthorityName.AuthorityNameValidator;
import it.chalmers.gamma.app.client.domain.authority.ClientAuthorityRepository;
import it.chalmers.gamma.app.common.PrettyName.PrettyNameValidator;
import it.chalmers.gamma.app.common.TextValue;
import it.chalmers.gamma.app.supergroup.SuperGroupFacade;
import it.chalmers.gamma.app.user.UserFacade;
import it.chalmers.gamma.security.authentication.AuthenticationExtractor;
import it.chalmers.gamma.security.authentication.UserAuthentication;
import jakarta.annotation.Nullable;
import jakarta.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -65,10 +67,11 @@ public ModelAndView getClients(
return mv;
}

@GetMapping("/clients/{id}")
public ModelAndView getClient(
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest,
@PathVariable("id") String clientUid) {
private ModelAndView createGetClient(
boolean htmxRequest,
String clientUid,
@Nullable String clientSecret,
@Nullable String apiKeyToken) {
if (!isValidUUID(clientUid)) {
return createClientNotFound(clientUid, htmxRequest);
}
Expand Down Expand Up @@ -112,10 +115,13 @@ public ModelAndView getClient(
}
}

mv.addObject("clientSecret", clientSecret);
mv.addObject("apiKeyToken", apiKeyToken);

return mv;
}

public ModelAndView createClientNotFound(String clientUid, boolean htmxRequest) {
private ModelAndView createClientNotFound(String clientUid, boolean htmxRequest) {
ModelAndView mv = new ModelAndView();
if (htmxRequest) {
mv.setViewName("client-details/not-found");
Expand All @@ -129,6 +135,13 @@ public ModelAndView createClientNotFound(String clientUid, boolean htmxRequest)
return mv;
}

@GetMapping("/clients/{id}")
public ModelAndView getClient(
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest,
@PathVariable("id") String clientUid) {
return createGetClient(htmxRequest, clientUid, null, null);
}

public static final class CreateClient {

@ValidatedWith(ClientRedirectUrlValidator.class)
Expand All @@ -137,8 +150,12 @@ public static final class CreateClient {
@ValidatedWith(PrettyNameValidator.class)
private String prettyName;

@ValidatedWith(TextValue.TextValueValidator.class)
private String svDescription;

@ValidatedWith(TextValue.TextValueValidator.class)
private String enDescription;

private boolean generateApiKey;
private boolean emailScope;

Expand Down Expand Up @@ -304,16 +321,13 @@ public ModelAndView getCreateClient(

mv.setViewName("client-details/page");

mv.addObject("clientUid", result.client().clientUid());
mv.addObject("client", result.client());
mv.addObject("clientAuthorities", new ArrayList<>());
mv.addObject("userApprovals", new ArrayList<>());
mv.addObject("clientSecret", result.clientSecret());
mv.addObject("apiKeyToken", result.apiKeyToken());

response.addHeader("HX-Push-Url", "/clients/" + result.client().clientUid());

return mv;
return createGetClient(
htmxRequest,
result.client().clientUid().toString(),
result.clientSecret(),
result.apiKeyToken());
}

@GetMapping("/clients/{id}/authorities")
Expand Down Expand Up @@ -512,4 +526,13 @@ public ModelAndView deleteClientAuthority(

return new ModelAndView("client-details/deleted-client-authority");
}

@PostMapping("/clients/{uid}/reset")
public ModelAndView resetClientSecret(
@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest,
@PathVariable("uid") UUID clientUid) {
String clientSecret = this.clientFacade.resetClientSecret(clientUid);

return createGetClient(htmxRequest, clientUid.toString(), clientSecret, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,12 @@ public List<ClientDTO> getAllMyClients() {
throw new IllegalStateException();
}

public String resetClientSecret(UUID clientUid) throws ClientNotFoundException {
public String resetClientSecret(UUID clientUid) {
ClientUid uid = new ClientUid(clientUid);

this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid));

Client client = this.clientRepository.get(uid).orElseThrow(ClientNotFoundException::new);
Client client = this.clientRepository.get(uid).orElseThrow();
ClientSecret.GeneratedClientSecret generated = ClientSecret.generate(passwordEncoder);

Client newClient = client.withClientSecret(generated.clientSecret());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</header>
<p>These are the credentials for your client. They will not be shown again.</p>
<div class="tuple-right-expand">
<div>
<div th:if="${clientSecret != null}">
<span>Client secret: </span>
<code th:text="${clientSecret}"></code>
</div>
Expand Down
8 changes: 6 additions & 2 deletions app/src/main/resources/templates/client-details/page.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,19 @@
</li>
</ul>
<footer>
<form data-hx-confirm="Are you sure you want to reset the client secret? The old client secret will be immediately revoked." th:data-hx-post="|/clients/${client.clientUid()}/reset|" data-hx-target="body">
<div th:replace="~{common/form-csrf}"></div>
<button class="outline contrast" data-loading-disable>Reset client secret</button>
</form>
<form data-hx-confirm="Are you sure you want to delete this client?" th:action="|/clients/${clientUid}|" th:method="delete">
<button class="outline contrast" data-loading-disable>Delete</button>
</form>
</footer>
</article>

<th:block th:if="${client.apiKey().isPresent()}" th:with="apiKey = ${client.apiKey().get()}">
<div class="contents" data-hx-headers='{"return-empty-on-delete":"true"}'>
<article th:replace="~{pages/api-key-details :: details}"></article>
<div class="contents">
<article th:replace="~{pages/api-key-details :: details(details = true)}"></article>
</div>
</th:block>

Expand Down
13 changes: 10 additions & 3 deletions app/src/main/resources/templates/pages/api-key-details.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<article th:replace="~{partial/api-key-credentials}"></article>
</th:block>

<article th:fragment="details">
<article th:fragment="details(details)">
<header>
Api key details
</header>
Expand All @@ -26,8 +26,15 @@
<span th:text="${apiKey.enDescription()}"></span>
</li>
</ul>
<footer>
<form data-hx-confirm="Are you sure you want to reset the token? The old token will immediately stop working."
<footer th:if="${details != null && details}">
<a th:href="|/api-keys/${apiKey.id()}|">
<button class="outline contrast">
More details
</button>
</a>
</footer>
<footer th:if="${details == null || !details}">
<form data-hx-confirm="Are you sure you want to reset the token? The old token will be immediately revoked."
data-hx-target="body"
th:data-hx-headers="${redirectUri != null} ? '{&quot;redirectUri&quot;: &quot;' + ${redirectUri} + '&quot;}' : null" th:data-hx-post="|/api-keys/${apiKey.id()}/reset|">
<div th:replace="~{common/form-csrf}"></div>
Expand Down

0 comments on commit 3f8c313

Please sign in to comment.