-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[#13691] Migrate storage + logic layer from google id #13755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/oidc
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package teammates.common.datatransfer; | ||
|
|
||
| public enum OidcProviderNameType { | ||
| GOOGLE("Google"), | ||
| MS_ENTRA("MSEntra"); | ||
|
|
||
| private final String providerName; | ||
|
|
||
| OidcProviderNameType(String providerName) { | ||
| this.providerName = providerName; | ||
| } | ||
|
|
||
| public String getProviderName() { | ||
| return providerName; | ||
| } | ||
|
|
||
| public String toString() { | ||
| return this.providerName; | ||
| } | ||
|
|
||
| public static OidcProviderNameType fromProviderName(String providerName) { | ||
| if (providerName == null) { | ||
| return null; | ||
| } | ||
|
|
||
| for (OidcProviderNameType provider : OidcProviderNameType.values()) { | ||
| if (provider.getProviderName().equals(providerName)) { | ||
| return provider; | ||
| } | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add newline at EOF |
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Issuer scheme is always HTTPS as per the spec. So what's the use of this constant |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| package teammates.common.util; | ||
|
|
||
| import java.net.URI; | ||
| import java.net.URISyntaxException; | ||
| import java.time.Duration; | ||
| import java.time.Instant; | ||
| import java.time.LocalDateTime; | ||
|
|
@@ -109,8 +111,10 @@ public final class FieldValidator { | |
| public static final String SESSION_END_TIME_FIELD_NAME = "end time"; | ||
| public static final String TIME_ZONE_FIELD_NAME = "time zone"; | ||
|
|
||
| public static final String GOOGLE_ID_FIELD_NAME = "Google ID"; | ||
| public static final int GOOGLE_ID_MAX_LENGTH = 254; | ||
| public static final String OIDC_ISSUER_FIELD_NAME = "OIDC issuer"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should there be a max length for issuer too? |
||
|
|
||
| public static final String OIDC_SUBJECT_FIELD_NAME = "OIDC subject"; | ||
| public static final int OIDC_SUBJECT_MAX_LENGTH = 255; | ||
|
|
||
| public static final String ROLE_FIELD_NAME = "access-level"; | ||
| public static final List<String> ROLE_ACCEPTED_VALUES = | ||
|
|
@@ -196,13 +200,17 @@ public final class FieldValidator { | |
| public static final String COURSE_ID_ERROR_MESSAGE_EMPTY_STRING = | ||
| EMPTY_STRING_ERROR_INFO + " " + HINT_FOR_CORRECT_COURSE_ID; | ||
|
|
||
| public static final String HINT_FOR_CORRECT_FORMAT_OF_GOOGLE_ID = | ||
| "A Google ID must be a valid id already registered with Google. " | ||
| + HINT_FOR_CORRECT_FORMAT_FOR_SIZE_CAPPED_NON_EMPTY_NO_SPACES; | ||
| public static final String GOOGLE_ID_ERROR_MESSAGE = | ||
| ERROR_INFO + " " + HINT_FOR_CORRECT_FORMAT_OF_GOOGLE_ID; | ||
| public static final String GOOGLE_ID_ERROR_MESSAGE_EMPTY_STRING = | ||
| EMPTY_STRING_ERROR_INFO + " " + HINT_FOR_CORRECT_FORMAT_OF_GOOGLE_ID; | ||
| public static final String HINT_FOR_CORRECT_OIDC_ISSUER = | ||
| "An OIDC issuer must be a case-sensitive https URL with a host, may include a port and path, " | ||
| + "and cannot contain query parameters or fragments."; | ||
Nsohko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| public static final String OIDC_ISSUER_ERROR_MESSAGE = | ||
| ERROR_INFO + " " + HINT_FOR_CORRECT_OIDC_ISSUER; | ||
|
|
||
| public static final String HINT_FOR_CORRECT_OIDC_SUBJECT = | ||
| "An OIDC subject must be a case-sensitive ASCII string. The value of a/an ${fieldName} should be " | ||
| + "no longer than ${maxLength} characters."; | ||
| public static final String OIDC_SUBJECT_ERROR_MESSAGE = | ||
| ERROR_INFO + " " + HINT_FOR_CORRECT_OIDC_SUBJECT; | ||
|
|
||
| public static final String HINT_FOR_CORRECT_TIME_ZONE = | ||
| "The value must be one of the values from the time zone dropdown selector."; | ||
|
|
@@ -263,11 +271,6 @@ public final class FieldValidator { | |
| public static final String REGEX_EMAIL = "^[\\w+-][\\w+!#$%&'*/=?^_`{}~-]*+(\\.[\\w+!#$%&'*/=?^_`{}~-]+)*+" | ||
| + "@([A-Za-z0-9-]+\\.)+[A-Za-z]+$"; | ||
|
|
||
| /** | ||
| * Allows English alphabet, numbers, underscore, dot and hyphen. | ||
| */ | ||
| public static final String REGEX_GOOGLE_ID_NON_EMAIL = "[a-zA-Z0-9_.-]+"; | ||
|
|
||
| private FieldValidator() { | ||
| // utility class | ||
| // Intentional private constructor to prevent instantiation. | ||
|
|
@@ -315,30 +318,59 @@ public static String getInvalidityInfoForGracePeriod(Duration gracePeriod) { | |
| } | ||
|
|
||
| /** | ||
| * Checks if {@code googleId} is not null, not empty, not longer than {@code GOOGLE_ID_MAX_LENGTH}, does | ||
| * not contain any invalid characters (| or %), AND is either a Google username (without the "@gmail.com") | ||
| * or a valid email address. | ||
| * @return An explanation of why the {@code googleId} is not acceptable. | ||
| * Returns an empty string if the {@code googleId} is acceptable. | ||
| * Checks if {@code issuer} is not null, not longer than {@code OIDC_ISSUER_MAX_LENGTH}, and is a | ||
| * valid OpenID Connect issuer identifier. | ||
| * | ||
| * <p>According to OpenID Connect Core 1.0, the issuer must be a case-sensitive URL using the https scheme that | ||
| * contains scheme, host, and optionally, port number and path components and no query or fragment components. | ||
| * | ||
| * @return An explanation of why the {@code issuer} is not acceptable. | ||
| * Returns an empty string if the {@code issuer} is acceptable. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong comment? "returns.." |
||
| */ | ||
| public static String getInvalidityInfoForGoogleId(String googleId) { | ||
|
|
||
| assert googleId != null; | ||
|
|
||
| boolean isValidFullEmail = isValidEmailAddress(googleId); | ||
| boolean isValidEmailWithoutDomain = StringHelper.isMatching(googleId, REGEX_GOOGLE_ID_NON_EMAIL); | ||
|
|
||
| if (googleId.isEmpty()) { | ||
| return getPopulatedEmptyStringErrorMessage(GOOGLE_ID_ERROR_MESSAGE_EMPTY_STRING, | ||
| GOOGLE_ID_FIELD_NAME, GOOGLE_ID_MAX_LENGTH); | ||
| } else if (isUntrimmed(googleId)) { | ||
| return WHITESPACE_ONLY_OR_EXTRA_WHITESPACE_ERROR_MESSAGE.replace("${fieldName}", GOOGLE_ID_FIELD_NAME); | ||
| } else if (googleId.length() > GOOGLE_ID_MAX_LENGTH) { | ||
| return getPopulatedErrorMessage(GOOGLE_ID_ERROR_MESSAGE, googleId, GOOGLE_ID_FIELD_NAME, | ||
| REASON_TOO_LONG, GOOGLE_ID_MAX_LENGTH); | ||
| } else if (!(isValidFullEmail || isValidEmailWithoutDomain)) { | ||
| return getPopulatedErrorMessage(GOOGLE_ID_ERROR_MESSAGE, googleId, GOOGLE_ID_FIELD_NAME, | ||
| REASON_INCORRECT_FORMAT, GOOGLE_ID_MAX_LENGTH); | ||
| public static String getInvalidityInfoForOidcIssuer(String issuer) { | ||
|
|
||
| assert issuer != null; | ||
|
|
||
| try { | ||
| URI issuerUri = new URI(issuer); | ||
| boolean isValid = Const.OIDC.ISSUER_SCHEME.equals(issuerUri.getScheme()) | ||
| && issuerUri.getHost() != null | ||
| && issuerUri.getUserInfo() == null | ||
| && issuerUri.getQuery() == null | ||
| && issuerUri.getFragment() == null | ||
| && issuerUri.isAbsolute() | ||
| && !issuerUri.isOpaque(); | ||
|
|
||
| if (!isValid) { | ||
| return getPopulatedErrorMessage(OIDC_ISSUER_ERROR_MESSAGE, issuer, OIDC_ISSUER_FIELD_NAME, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be simplified to reduce duplication? |
||
| REASON_INCORRECT_FORMAT); | ||
| } | ||
|
|
||
| } catch (URISyntaxException e) { | ||
| return getPopulatedErrorMessage(OIDC_ISSUER_ERROR_MESSAGE, issuer, OIDC_ISSUER_FIELD_NAME, | ||
| REASON_INCORRECT_FORMAT); | ||
| } | ||
|
|
||
| return ""; | ||
| } | ||
Nsohko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * Checks if {@code subject} is not null, not longer than {@code OIDC_SUBJECT_MAX_LENGTH}, and | ||
| * contains only ASCII characters as required by OpenID Connect Core 1.0. | ||
| * | ||
| * @return An explanation of why the {@code subject} is not acceptable. | ||
| * Returns an empty string if the {@code subject} is acceptable. | ||
| */ | ||
| public static String getInvalidityInfoForOidcSubject(String subject) { | ||
|
|
||
| assert subject != null; | ||
|
|
||
| if (subject.length() > OIDC_SUBJECT_MAX_LENGTH) { | ||
| return getPopulatedErrorMessage(OIDC_SUBJECT_ERROR_MESSAGE, subject, OIDC_SUBJECT_FIELD_NAME, | ||
| REASON_TOO_LONG, OIDC_SUBJECT_MAX_LENGTH); | ||
| } else if (!isAsciiString(subject)) { | ||
| return getPopulatedErrorMessage(OIDC_SUBJECT_ERROR_MESSAGE, subject, OIDC_SUBJECT_FIELD_NAME, | ||
| REASON_INCORRECT_FORMAT, OIDC_SUBJECT_MAX_LENGTH); | ||
| } | ||
| return ""; | ||
| } | ||
|
|
@@ -998,6 +1030,10 @@ private static boolean isUntrimmed(String value) { | |
| return value.length() != value.trim().length(); | ||
| } | ||
|
|
||
| private static boolean isAsciiString(String value) { | ||
| return value.chars().allMatch(character -> character <= 0x7F); | ||
| } | ||
|
|
||
| /** | ||
| * Checks whether a given text input represents a format of a valid email address. | ||
| * @param email text input which needs the validation | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe can use
StringHelper.isEmptyfor null check