Skip to content
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

Implement oidc #628

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open

Implement oidc #628

wants to merge 25 commits into from

Conversation

Jeidnx
Copy link

@Jeidnx Jeidnx commented Jun 18, 2023

Copy link
Member

@FireMasterK FireMasterK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I don't like is there's too much business logic in ServerLaunche, I would ideally like to move it to a new file like OidcHandlers.java or to the existing UserHandlers class.

@Jeidnx
Copy link
Author

Jeidnx commented Nov 12, 2024

I have cleaned up the code and made sure everything works. Here are a few things worth mentioning:

  • This only supports providers which have the openid connect discovery standard (.well-known/openid-configuration) implemented, which should be all relevant providers.
  • User deletion currently only works if the provider supports the optional max_age parameter and properly returns the auth_time claim. We could drop this restriction, but that would allow one-click deletion of accounts without verifying the identity of the user.
  • This also only works with providers which support the PKCE code authorization flow, which again should be most of them.

Please let me know if there are any questions or concerns. I have tested this and from my view this could be merged

edit: Found the alternative for TokenRequest..

Comment on lines +537 to +541
for (int i = 0; i < Constants.OIDC_PROVIDERS.size(); i++) {
OidcProvider curr = Constants.OIDC_PROVIDERS.get(i);
if (curr == null || !curr.name.equals(provider)) continue;
return curr;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (int i = 0; i < Constants.OIDC_PROVIDERS.size(); i++) {
OidcProvider curr = Constants.OIDC_PROVIDERS.get(i);
if (curr == null || !curr.name.equals(provider)) continue;
return curr;
}
for (OidcProvider curr : Constants.OIDC_PROVIDERS) {
if (curr != null && curr.name.equals(provider)) return curr;
}

.state(new State(state))
.nonce(data.getOidNonce()).build();

if (redirectUri.equals(Constants.FRONTEND_URL + "/login")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably shouldn't hardcode the url path here, maybe it makes sense to parse the domain of the redirectUri and see if equals Constants.FRONTEND_URL? Or we could just do a redirectUri.startsWith(Constants.FRONTEND_URL + "/").

return HttpResponse.ok200().withHtml(
"<!DOCTYPE html><html style=\"color-scheme: dark light;\"><body>" +
"<h3>Warning:</h3> You are trying to give <pre style=\"font-size: 1.2rem;\">" +
redirectUri +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redirectUri needs to be HTML escaped or checked if it's a real URL, otherwise that would allow HTML injection.


OidcData data = DatabaseHelper.getOidcData(authResponse.getState().toString());
if (data == null) {
return HttpResponse.ofCode(400).withHtml(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we don't provide any styling or color-scheme: dark light;, withPlainText would probably be better to not become flashed in dark mode

AuthorizationCode code = authResponse.getAuthorizationCode();

if (code == null) {
return HttpResponse.ofCode(400).withHtml(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above (withPlainText)

Comment on lines +210 to +213
return HttpResponse.ofCode(400).withHtml("Received a bad token. Please try again");
} catch (JOSEException e) {
System.err.println("Token processing error: " + e);
return HttpResponse.ofCode(500).withHtml("Internal processing error. Please try again");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withPlainText

UserInfoResponse userInfoResponse = UserInfoResponse.parse(ur.toHTTPRequest().send());

if (!userInfoResponse.indicatesSuccess()) {
return HttpResponse.ofCode(500).withHtml(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withPlainText


cr.select(root).where(root.get("sub").in(sub));

OidcUserData dbuser = s.createQuery(cr).uniqueResult();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
OidcUserData dbuser = s.createQuery(cr).uniqueResult();
OidcUserData dbUser = s.createQuery(cr).uniqueResult();

Comment on lines +283 to +288
for (OidcProvider oidcProvider : Constants.OIDC_PROVIDERS) {
if (oidcProvider.name.equals(oidcUserData.getProvider())) {
provider = oidcProvider;
break;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (OidcProvider oidcProvider : Constants.OIDC_PROVIDERS) {
if (oidcProvider.name.equals(oidcUserData.getProvider())) {
provider = oidcProvider;
break;
}
}
provider = ServerLauncher.getOidcProvider(oicdUserDate.getProvider());

Comment on lines +322 to +369
AuthenticationSuccessResponse sr = parseOidcUri(requestUri);

OidcData data = DatabaseHelper.getOidcData(sr.getState().toString());

if (data == null) {
return HttpResponse.ofCode(400).withHtml(
"Your oidc provider sent invalid state data. Try again or contact your oidc admin"
);
}

String redirect = data.data.split("\\|")[1];
String session = data.data.split("\\|")[0];

URI callback = new URI(Constants.PUBLIC_URL + "/oidc/" + provider.name + "/delete");
AuthorizationCode code = sr.getAuthorizationCode();

if (code == null) {
return HttpResponse.ofCode(400).withHtml(
"Your oidc provider sent an invalid code. Try again or contact your oidc admin"
);
}

AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callback, data.getOidVerifier());

ClientAuthentication clientAuth = new ClientSecretBasic(provider.clientID, provider.clientSecret);

TokenRequest tokenRequest = new TokenRequest.Builder(provider.tokenUri, clientAuth, codeGrant).build();
TokenResponse tokenResponse = OIDCTokenResponseParser.parse(tokenRequest.toHTTPRequest().send());

if (!tokenResponse.indicatesSuccess()) {
TokenErrorResponse errorResponse = tokenResponse.toErrorResponse();
return HttpResponse.ofCode(500).withHtml("Failure while trying to request token:\n\n" + errorResponse.getErrorObject().getDescription());
}

OIDCTokenResponse successResponse = (OIDCTokenResponse) tokenResponse.toSuccessResponse();

JWT idToken = JWTParser.parse(successResponse.getOIDCTokens().getIDTokenString());

IDTokenClaimsSet claims;
try {
claims = provider.validator.validate(idToken, data.getOidNonce());
} catch (BadJOSEException e) {
System.err.println("Invalid token received: " + e);
return HttpResponse.ofCode(400).withHtml("Received a bad token. Please try again");
} catch (JOSEException e) {
System.err.println("Token processing error: " + e);
return HttpResponse.ofCode(500).withHtml("Internal processing error. Please try again");
}
Copy link
Member

@Bnyro Bnyro Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's just a lot of duplicate code from oidcLoginCallback, it would certainly make sense to refactor the common code into a new method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants