Add consent page (GUI)

This commit is contained in:
Andreas Svanberg 2025-04-22 00:35:54 +02:00
parent c8f28d8283
commit 0c55c25abf
Signed by: ansv7779
GPG Key ID: 729B051CFFD42F92
2 changed files with 121 additions and 1 deletions
src/main
java/se/su/dsv/oauth2/web/oauth2
resources/templates

@ -1,12 +1,91 @@
package se.su.dsv.oauth2.web.oauth2;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.ErrorResponseException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
@Controller
public class ConsentController {
private final AuthorizationServerSettings authorizationServerSettings;
private final RegisteredClientRepository registeredClientRepository;
public ConsentController(
final AuthorizationServerSettings authorizationServerSettings,
final RegisteredClientRepository registeredClientRepository)
{
this.authorizationServerSettings = authorizationServerSettings;
this.registeredClientRepository = registeredClientRepository;
}
@GetMapping("/oauth2/consent")
public String showConsentForm() {
public String showConsentForm(
Model model,
UriComponentsBuilder uriComponentsBuilder,
@RequestParam("scope") String scopeString,
@RequestParam("client_id") String clientId,
@RequestParam("state") String state)
{
RegisteredClient client = registeredClientRepository.findByClientId(clientId);
if (client == null) {
throw new ErrorResponseException(HttpStatus.BAD_REQUEST);
}
model.addAttribute("clientName", client.getClientName());
model.addAttribute("clientDomain", getClientDomain(client));
String authorizationUrl = uriComponentsBuilder
.path(authorizationServerSettings.getAuthorizationEndpoint())
.toUriString();
model.addAttribute("authorizationUrl", authorizationUrl);
Set<String> scopes = getRequestScopes(scopeString);
model.addAttribute("scopes", scopes);
model.addAttribute("clientId", clientId);
model.addAttribute("state", state);
return "consent";
}
private static String getClientDomain(final RegisteredClient client) {
return client.getRedirectUris()
.stream()
.map(UriComponentsBuilder::fromUriString)
.map(UriComponentsBuilder::build)
.map(uri -> {
String scheme = uri.getScheme();
String host = uri.getHost();
return scheme + "://" + host;
})
.findAny()
.orElseThrow(() -> new ErrorResponseException(HttpStatus.BAD_REQUEST));
}
private static Set<String> getRequestScopes(final String scopeString) {
if (scopeString == null) {
return Set.of();
}
return Arrays.stream(scopeString.split(" "))
.filter(s -> !s.isBlank())
.collect(Collectors.toSet());
}
@ModelAttribute("currentUser")
public Authentication authentication(Authentication authentication) {
return authentication;
}
}

@ -1,3 +1,44 @@
@import org.springframework.security.core.Authentication
@import java.util.Set
@param String clientId
@param String clientName
@param String clientDomain
@param String authorizationUrl
@param String state
@param Authentication currentUser
@param Set<String> scopes
@template.base(title = "Consent", content = @`
<h1>Consent</h1>
<p>
The application <strong>${clientName}</strong> located at
<strong>${clientDomain}</strong> wants to access your information.
</p>
<p>
See below for what information it is requesting and select what information
you're willing to share.
</p>
<form method="post" action="${authorizationUrl}">
<input type="hidden" name="client_id" value="${clientId}">
<input type="hidden" name="state" value="${state}">
<ul class="list-group mb-3">
<li class="list-group-item">
Account name: ${currentUser.getName()}
</li>
@for (var scope : scopes)
<li class="list-group-item">
<input class="form-check-input" type="checkbox" name="scope" value="${scope}" id="scope_${scope}" checked>
<label class="form-check-label" for="scope_${scope}">
${scope}
</label>
</li>
@endfor
</ul>
<button type="submit" class="btn btn-primary">Consent to sharing the above information</button>
<button type="submit" formaction="/oauth2/consent" class="btn btn-link">Deny</button>
</form>
`)