1313import de .tum .cit .aet .artemis .account .dto .LoginOptionsDTO ;
1414import de .tum .cit .aet .artemis .account .dto .LoginOptionsDTO .LoginMethod ;
1515import de .tum .cit .aet .artemis .account .repository .UserRepository ;
16- import de .tum .cit .aet .artemis .account .service .ldap .LdapUserDto ;
17- import de .tum .cit .aet .artemis .account .service .ldap .LdapUserService ;
1816import de .tum .cit .aet .artemis .core .security .SecurityUtils ;
1917
2018/**
21- * Service responsible for determining the appropriate login options (such as password, OIDC, or SAML2)
22- * for a user based on their identifier (login or email).
19+ * Determines which login option (password, OIDC, or SAML2) the login form should offer for a given identifier, so that the
20+ * identifier-first form can either show a password field or send the user to the configured identity provider.
21+ * <p>
22+ * The decision is made from local account state alone. This backs an unauthenticated endpoint, so its answer must be
23+ * derivable from what the caller already supplies: it deliberately does not consult the configured directory, which would
24+ * both make the response depend on whether the identifier exists there and let an unauthenticated caller drive queries
25+ * against it.
2326 */
2427@ Profile (PROFILE_CORE )
2528@ Service
@@ -28,8 +31,6 @@ public class LoginOptionsService {
2831
2932 private final UserRepository userRepository ;
3033
31- private final Optional <LdapUserService > ldapUserService ;
32-
3334 @ Value ("${artemis.user-management.oidc.enabled:false}" )
3435 private boolean oidcEnabled ;
3536
@@ -42,13 +43,19 @@ public class LoginOptionsService {
4243 @ Value ("${info.saml2.buttonLabel:TUM Login}" )
4344 private String samlDisplayName ;
4445
45- public LoginOptionsService (UserRepository userRepository , Optional < LdapUserService > ldapUserService ) {
46+ public LoginOptionsService (UserRepository userRepository ) {
4647 this .userRepository = userRepository ;
47- this .ldapUserService = ldapUserService ;
4848 }
4949
5050 /**
5151 * Determines which login method the user should use based on their identifier (login or email).
52+ * <p>
53+ * An internal account is the only kind that authenticates against a password stored in Artemis, so it is the only case
54+ * answered with the password form. Everything else - an externally managed account, and an identifier this instance has
55+ * never seen - is sent to the external provider, which is also where a first-time user gets provisioned. Those two are
56+ * answered identically on purpose, so the response does not distinguish a known identifier from an unknown one.
57+ * <p>
58+ * Falls back to the password form when no external provider is configured, and for a blank identifier.
5259 *
5360 * @param emailOrLogin the username or email address entered by the user
5461 * @return the LoginOptionsDTO containing the determined login method and the display name of the provider
@@ -61,30 +68,17 @@ public LoginOptionsDTO getLoginOptions(String emailOrLogin) {
6168 boolean isEmail = SecurityUtils .isEmail (sanitizedInput );
6269 // only project the internal flag instead of loading the whole user entity: empty means the user is not in the database
6370 Optional <Boolean > internalFlag = isEmail ? userRepository .isInternalUserByEmailIgnoreCase (sanitizedInput ) : userRepository .isInternalUserByLogin (sanitizedInput );
64- if (internalFlag .isPresent ()) {
65- if (internalFlag .get ()) {
66- return new LoginOptionsDTO (LoginMethod .PASSWORD , null );
67- }
68- else {
69- return getExternalUser ();
70- }
71- }
72- if (ldapUserService .isPresent ()) {
73- Optional <LdapUserDto > ldapUser = isEmail ? ldapUserService .get ().findByAnyEmail (sanitizedInput ) : ldapUserService .get ().findByLogin (sanitizedInput );
74- // if user has a university account
75- if (ldapUser .isPresent ()) {
76- return getExternalUser ();
77- }
78- // if not: this is an internal user
79- else {
80- return new LoginOptionsDTO (LoginMethod .PASSWORD , null );
81- }
82- }
83- // If user is new and ldap is disabled - provide the SSO authentication option
84- if (oidcEnabled || samlEnabled ) {
85- return getExternalUser ();
71+ // An internal account is the only kind that authenticates against a password stored in Artemis, so it is the only case that
72+ // needs the password form. Everything else - an externally managed account, and an identifier this instance has never seen -
73+ // is sent to the external provider, which is also where a first-time user gets provisioned.
74+ //
75+ // The two are answered identically on purpose. This endpoint is unauthenticated, so its answer must be derivable from what the
76+ // caller already knows; it deliberately does not consult the configured directory, which would both make the response depend on
77+ // whether the identifier exists there and let an unauthenticated caller drive queries against it.
78+ if (internalFlag .isPresent () && internalFlag .get ()) {
79+ return new LoginOptionsDTO (LoginMethod .PASSWORD , null );
8680 }
87- return new LoginOptionsDTO ( LoginMethod . PASSWORD , null );
81+ return getExternalUser ( );
8882 }
8983
9084 /**
0 commit comments