Skip to content

Commit

Permalink
Merge pull request #4193 from IQSS/3153-login-math
Browse files Browse the repository at this point in the history
3153 login math
  • Loading branch information
kcondon authored Oct 19, 2017
2 parents 9294bea + fd743e2 commit 509f8b3
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 7 deletions.
7 changes: 0 additions & 7 deletions doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -437,13 +437,6 @@ Place this ``user-add.json`` file in your current directory and run the followin

curl -d @user-add.json -H "Content-type:application/json" "$SERVER_URL/api/builtin-users?password=$NEWUSER_PASSWORD&key=$BUILTIN_USERS_KEY"

Retrieving the API Token of a Builtin User
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To retrieve the API token of a builtin user, given that user's password, use the curl command below::

curl "$SERVER_URL/api/builtin-users/$DV_USER_NAME/api-token?password=$DV_USER_PASSWORD"

Roles
~~~~~

Expand Down
7 changes: 7 additions & 0 deletions doc/sphinx-guides/source/installation/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1209,3 +1209,10 @@ You can replace the default dataset metadata fields that are displayed above fil
``curl http://localhost:8080/api/admin/settings/:CustomDatasetSummaryFields -X PUT -d 'producer,subtitle,alternativeTitle'``

You have to put the datasetFieldType name attribute in the :CustomDatasetSummaryFields setting for this to work.

:AllowApiTokenLookupViaApi
++++++++++++++++++++++++++

Dataverse 4.8.1 and below allowed API Token lookup via API but for better security this has been disabled by default. Set this to true if you really want the old behavior.

``curl -X PUT -d 'true' http://localhost:8080/api/admin/settings/:AllowApiTokenLookupViaApi``
54 changes: 54 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/LoginPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.validator.ValidatorException;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
Expand Down Expand Up @@ -101,6 +104,11 @@ public enum EditMode {LOGIN, SUCCESS, FAILED};

private String redirectPage = "dataverse.xhtml";
private AuthenticationProvider authProvider;
private int numFailedLoginAttempts;
Random random;
long op1;
long op2;
Long userSum;

public void init() {
Iterator<String> credentialsIterator = authSvc.getAuthenticationProviderIdsOfType( CredentialsAuthenticationProvider.class ).iterator();
Expand All @@ -109,6 +117,7 @@ public void init() {
}
resetFilledCredentials(null);
authProvider = authSvc.getAuthenticationProvider(systemConfig.getDefaultAuthProvider());
random = new Random();
}

public List<AuthenticationProviderDisplayInfo> listCredentialsAuthenticationProviders() {
Expand Down Expand Up @@ -179,6 +188,9 @@ public String login() {


} catch (AuthenticationFailedException ex) {
numFailedLoginAttempts++;
op1 = new Long(random.nextInt(10));
op2 = new Long(random.nextInt(10));
AuthenticationResponse response = ex.getResponse();
switch ( response.getStatus() ) {
case FAIL:
Expand Down Expand Up @@ -256,4 +268,46 @@ public String getLoginButtonText() {
return BundleUtil.getStringFromBundle("login.button", Arrays.asList("???"));
}
}

public int getNumFailedLoginAttempts() {
return numFailedLoginAttempts;
}

public boolean isRequireExtraValidation() {
if (numFailedLoginAttempts > 2) {
return true;
} else {
return false;
}
}

public long getOp1() {
return op1;
}

public long getOp2() {
return op2;
}

public Long getUserSum() {
return userSum;
}

public void setUserSum(Long userSum) {
this.userSum = userSum;
}

// TODO: Consolidate with SendFeedbackDialog.validateUserSum?
public void validateUserSum(FacesContext context, UIComponent component, Object value) throws ValidatorException {
// The FacesMessage text is on the xhtml side.
FacesMessage msg = new FacesMessage("");
ValidatorException validatorException = new ValidatorException(msg);
if (value == null) {
throw validatorException;
}
if (op1 + op2 != (Long) value) {
throw validatorException;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class SendFeedbackDialog implements java.io.Serializable {
private String userMessage = "";
private String messageSubject = "";
private String messageTo = "";
// FIXME: Remove "support@thedata.org". There's no reason to email the Dataverse *project*. People should email the *installation* instead.
private String defaultRecipientEmail = "support@thedata.org";
Long op1, op2, userSum;
// Either the dataverse or the dataset that the message is pertaining to
Expand Down Expand Up @@ -161,6 +162,7 @@ public void validateUserSum(FacesContext context, UIComponent component, Object

if (op1 + op2 !=(Long)value) {

// TODO: Remove this English "Sum is incorrect" string. contactFormFragment.xhtml uses contact.sum.invalid instead.
FacesMessage msg
= new FacesMessage("Sum is incorrect, please try again.");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/api/BuiltinUsers.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import edu.harvard.iq.dataverse.authorization.providers.builtin.PasswordEncryption;
import edu.harvard.iq.dataverse.authorization.users.ApiToken;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.logging.Level;
Expand Down Expand Up @@ -53,6 +54,14 @@ public class BuiltinUsers extends AbstractApiBean {
@GET
@Path("{username}/api-token")
public Response getApiToken( @PathParam("username") String username, @QueryParam("password") String password ) {
boolean disabled = true;
boolean lookupAllowed = settingsSvc.isTrueForKey(SettingsServiceBean.Key.AllowApiTokenLookupViaApi, false);
if (lookupAllowed) {
disabled = false;
}
if (disabled) {
return error(Status.FORBIDDEN, "This API endpoint has been disabled.");
}
BuiltinUser u = null;
if (retrievingApiTokenViaEmailEnabled) {
u = builtinUserSvc.findByUsernameOrEmail(username);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class SettingsServiceBean {
* So there.
*/
public enum Key {
AllowApiTokenLookupViaApi,
/**
* Ordered, comma-separated list of custom fields to show above the fold
* on dataset page such as "data_type,sample,pdb"
Expand Down
17 changes: 17 additions & 0 deletions src/main/webapp/loginpage.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,23 @@
</div>
</div>
</ui:repeat>

<!-- validation -->
<div class="form-group" jsf:rendered="#{LoginPage.requireExtraValidation}">
<div class="col-sm-offset-4 col-sm-8">
<p>
<h:outputText styleClass="highlightBold" value="#{bundle['contact.question']}"/> <span class="glyphicon glyphicon-asterisk text-danger" title="#{bundle.requiredField}"/>
</p>
<h:outputFormat value="#{LoginPage.op1} + #{LoginPage.op2} = "/>
<p:inputText id="messageSum" label="Sum" size="4" value="#{LoginPage.userSum}" converterMessage="#{bundle['contact.sum.converterMessage']}"
required="#{param['DO_VALIDATION']}" requiredMessage="#{bundle['contact.sum.required']}"
validatorMessage="#{bundle['contact.sum.invalid']}" validator="#{LoginPage.validateUserSum}">
<f:convertNumber integerOnly="true" type="number"/>
</p:inputText>
<h:message for="messageSum" styleClass="bg-danger text-danger"/>
</div>
</div>

<div class="form-group">
<div class="col-sm-offset-4 col-sm-9 button-block">
<p:commandButton id="login" styleClass="btn btn-default" value="#{bundle.login}" update="@all" action="#{LoginPage.login}"/>
Expand Down
19 changes: 19 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/api/BuiltinUsersIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import javax.json.Json;
import javax.json.JsonObjectBuilder;
import static javax.ws.rs.core.Response.Status.OK;
import static javax.ws.rs.core.Response.Status.FORBIDDEN;
import static junit.framework.Assert.assertEquals;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
Expand All @@ -37,6 +38,11 @@ public class BuiltinUsersIT {
@BeforeClass
public static void setUp() {
RestAssured.baseURI = UtilIT.getRestAssuredBaseUri();

Response removeIdentifierGenerationStyle = UtilIT.deleteSetting(SettingsServiceBean.Key.AllowApiTokenLookupViaApi);
removeIdentifierGenerationStyle.then().assertThat()
.statusCode(200);

}

@Test
Expand Down Expand Up @@ -171,6 +177,15 @@ public void testLogin() {
String createdToken = createdUser.getString("data.apiToken");
logger.info(createdToken);

Response getApiTokenShouldFail = getApiTokenUsingUsername(usernameToCreate, usernameToCreate);
getApiTokenShouldFail.then().assertThat()
.body("message", equalTo("This API endpoint has been disabled."))
.statusCode(FORBIDDEN.getStatusCode());

Response setAllowApiTokenLookupViaApi = UtilIT.setSetting(SettingsServiceBean.Key.AllowApiTokenLookupViaApi, "true");
setAllowApiTokenLookupViaApi.then().assertThat()
.statusCode(OK.getStatusCode());

Response getApiTokenUsingUsername = getApiTokenUsingUsername(usernameToCreate, usernameToCreate);
getApiTokenUsingUsername.prettyPrint();
assertEquals(200, getApiTokenUsingUsername.getStatusCode());
Expand All @@ -189,6 +204,10 @@ public void testLogin() {
assertEquals(createdToken, retrievedTokenUsingEmail);
}

Response removeIdentifierGenerationStyle = UtilIT.deleteSetting(SettingsServiceBean.Key.AllowApiTokenLookupViaApi);
removeIdentifierGenerationStyle.then().assertThat()
.statusCode(200);

}

@Test
Expand Down

0 comments on commit 509f8b3

Please sign in to comment.