I am curious about this login step in the test case in Spring Authorization Server defaultAuthorizationServer sample project test case that does not have a client-id associated but the user can still login:
@Test
public void whenLoggingInAndRequestingTokenThenRedirectsToClientApplication() throws IOException {
// Log in
this.webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
this.webClient.getOptions().setRedirectEnabled(false);
signIn(this.webClient.getPage("/login"), "user1", "password");
// Request token
WebResponse response = this.webClient.getPage(AUTHORIZATION_REQUEST).getWebResponse();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.MOVED_PERMANENTLY.value());
String location = response.getResponseHeaderValue("location");
assertThat(location).startsWith(REDIRECT_URI);
assertThat(location).contains("code=");
}
I ran this test case in my project. I have a AuthenticationProvider implementation and I checked for the clientId and it is null based on the RequestCache. Will there be a case where the user can login to Authorization server without a client id? My thoughts are that there will always be a client app or client-id associated when a user logs in to the login page.
The following is my AuthenticationProvider implementation:
@Service
public class AuthenticationCallout implements AuthenticationProvider {
private static final Logger LOG = LoggerFactory.getLogger(AuthenticationCallout.class);
private RequestCache requestCache;
private WebClient.Builder webClientBuilder;
public AuthenticationCallout(WebClient.Builder webClientBuilder, RequestCache requestCache) {
this.webClientBuilder = webClientBuilder;
this.requestCache = requestCache;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
LOG.info("authenticate with username and password");
final String clientId = ClientIdUtil.getClientId(requestCache);
LOG.info("clientId: {}", clientId); //client-id is always null because the login does not have a client association
...
}
//ClientIdUtil implmentation
public class ClientIdUtil {
private static final Logger LOG = LoggerFactory.getLogger(ClientIdUtil.class);
public static String getClientId(RequestCache requestCache) {
var requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
var request = requestAttributes.getRequest();
var response = requestAttributes.getResponse();
var savedRequest = requestCache.getRequest(request, response);
return ClientIdUtil.getParameter(savedRequest, OAuth2ParameterNames.CLIENT_ID);
}
}
If the user initiates authorization from the client (via a redirect to log in or to authorize a client), there will be a request in the RequestCache
. However, the authorization server is still just a normal application, with its own login. So a user can (and in more advanced authorization server deployments, will) log directly into the authorization server.
Imagine a scenario where the user forgot their password, so they click "Forgot Password" on a desktop, and have an email sent to them. They click a link in the email on their phone to reset the password, and log in successfully on their phone afterwards. There will be no request in the RequestCache
. There are many other scenarios where a user would log in first (e.g. to update their profile, password, security options, visit a dashboard, etc.).
In the test case, it is indeed the case that the user logs in first, and then goes through the authorization code flow.