Skip to content

Commit

Permalink
A quick implementation of a mechanism for disabling new account signu…
Browse files Browse the repository at this point in the history
…ps for

remote auth. of specific type (without blocking all the existing accounts of
the type). #9111
  • Loading branch information
landreev committed Oct 31, 2022
1 parent 42e2b59 commit 25521d8
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edu.harvard.iq.dataverse.authorization.providers.oauth2;

import edu.harvard.iq.dataverse.DataverseSession;
import edu.harvard.iq.dataverse.authorization.AuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
import edu.harvard.iq.dataverse.authorization.UserRecordIdentifier;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
Expand All @@ -27,6 +28,8 @@

import static edu.harvard.iq.dataverse.util.StringUtil.toOption;
import edu.harvard.iq.dataverse.util.SystemConfig;
import java.util.ArrayList;
import java.util.Collections;
import org.omnifaces.util.Faces;

/**
Expand All @@ -45,6 +48,8 @@ public class OAuth2LoginBackingBean implements Serializable {
private String responseBody;
Optional<String> redirectPage = Optional.empty();
private OAuth2Exception error;
private boolean disabled = false;
private boolean signUpDisabled = false;
/**
* TODO: Only used in exchangeCodeForToken(). Make local var in method.
*/
Expand Down Expand Up @@ -96,13 +101,26 @@ public void exchangeCodeForToken() throws IOException {
AbstractOAuth2AuthenticationProvider idp = oIdp.get();
oauthUser = idp.getUserRecord(code.get(), systemConfig.getOAuth2CallbackUrl());

// Throw an error if this authentication method is disabled:
if (isProviderDisabled(idp.getId())) {
disabled = true;
throw new OAuth2Exception(-1, "", "This authentication method ("+idp.getId()+") is currently disabled. Please log in using one of the supported methods.");
}

UserRecordIdentifier idtf = oauthUser.getUserRecordIdentifier();
AuthenticatedUser dvUser = authenticationSvc.lookupUser(idtf);

if (dvUser == null) {
// need to create the user
newAccountPage.setNewUser(oauthUser);
Faces.redirect("/oauth2/firstLogin.xhtml");
// need to create the user - unless signups are disabled
// for this authentication method; in which case, throw
// an error:
if (systemConfig.isSignupDisabledForRemoteAuthProvider(idp.getId())) {
signUpDisabled = true;
throw new OAuth2Exception(-1, "", "Sorry, signup for new accounts using "+idp.getId()+" authentication is currently disabled.");
} else {
newAccountPage.setNewUser(oauthUser);
Faces.redirect("/oauth2/firstLogin.xhtml");
}

} else {
// login the user and redirect to HOME of intended page (if any).
Expand Down Expand Up @@ -271,4 +289,32 @@ public List<AbstractOAuth2AuthenticationProvider> getProviders() {
public boolean isOAuth2ProvidersDefined() {
return !authenticationSvc.getOAuth2Providers().isEmpty();
}

public boolean isDisabled() {
return disabled;
}

public boolean isSignUpDisabled() {
return signUpDisabled;
}

private boolean isProviderDisabled(String providerId) {
// Compare this provider id against the list of *enabled* auth providers
// returned by the Authentication Service:
List<AuthenticationProvider> idps = new ArrayList<>(authenticationSvc.getAuthenticationProviders());

// for the tests to work:
if (idps.isEmpty()) {
return false;
}

for (AuthenticationProvider idp : idps) {
if (idp != null) {
if (providerId.equals(idp.getId())) {
return false;
}
}
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,11 @@ Whether Harvesting (OAI) service is enabled
/*
* Allow a custom JavaScript to control values of specific fields.
*/
ControlledVocabularyCustomJavaScript
ControlledVocabularyCustomJavaScript,
/**
* A compound setting for disabling signup for remote Auth providers:
*/
AllowRemoteAuthSignUp
;

@Override
Expand Down Expand Up @@ -668,7 +672,39 @@ public Long getValueForCompoundKeyAsLong(Key key, String param){
}

}

/**
* Same, but with Booleans
* (returns null if not set; the calling method will decide what that shouldall
* default to)
* Example:
* :AllowRemoteAuthSignUp {"default":"true","google":"false"}
*/

public Boolean getValueForCompoundKeyAsBoolean(Key key, String param) {

String val = this.getValueForKey(key);

if (val == null) {
return null;
}

try (StringReader rdr = new StringReader(val)) {
JsonObject settings = Json.createReader(rdr).readObject();
if (settings.containsKey(param)) {
return Boolean.parseBoolean(settings.getString(param));
} else if (settings.containsKey("default")) {
return Boolean.parseBoolean(settings.getString("default"));
} else {
return null;
}

} catch (Exception e) {
logger.log(Level.WARNING, "Incorrect setting. Could not convert \"{0}\" from setting {1} to boolean: {2}", new Object[]{val, key.toString(), e.getMessage()});
return null;
}

}
/**
* Return the value stored, or the default value, in case no setting by that
* name exists. The main difference between this method and the other {@code get()}s
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/util/SystemConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -1228,4 +1228,15 @@ public Map<String, String[]> getCurationLabels() {
}
return labelMap;
}

public boolean isSignupDisabledForRemoteAuthProvider(String providerId) {
Boolean ret = settingsService.getValueForCompoundKeyAsBoolean(SettingsServiceBean.Key.AllowRemoteAuthSignUp, providerId);

// we default to false if it's null, i.e. if not present:
if (ret == null) {
return false;
}

return !ret;
}
}
2 changes: 1 addition & 1 deletion src/main/webapp/oauth2/callback.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<ui:define name="body">
<div class="alert alert-danger" role="alert" style="margin-top:3em;">
<p>
<h:outputFormat value="#{bundle['oauth2.callback.message']}" escape="false">
<h:outputFormat value="#{bundle['oauth2.callback.message']}" escape="false" rendered="#{(!OAuth2Page.disabled) and (!OAuth2Page.signUpDisabled)}">
<f:param value="#{systemConfig.guidesBaseUrl}"/>
<f:param value="#{systemConfig.guidesVersion}"/>
</h:outputFormat>
Expand Down

0 comments on commit 25521d8

Please sign in to comment.