Skip to content

Commit

Permalink
feat(engine): introduce password policies for engine-managed user
Browse files Browse the repository at this point in the history
* a policy that enforces password length and complexity is enabled by
default
* policies can be created via Java API
* an engine can be configured to use a custom policy or don't use any
policy

related to CAM-9929, CAM-9930
  • Loading branch information
mboskamp committed Mar 21, 2019
1 parent dcbde74 commit 80671e1
Show file tree
Hide file tree
Showing 19 changed files with 812 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright © 2013-2019 camunda services GmbH and various authors (info@camunda.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.engine.rest.dto.passwordPolicy;

/**
* @author Miklas Boskamp
*/
public class PasswordDto {

private String password;

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright © 2013-2019 camunda services GmbH and various authors (info@camunda.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.engine.rest.dto.passwordPolicy;

import java.util.ArrayList;
import java.util.List;

import org.camunda.bpm.engine.pwpolicy.PasswordPolicyRule;

/**
* @author Miklas Boskamp
*/
public class PasswordPolicyDto {
private List<PasswordPolicyRuleDto> rules = new ArrayList<PasswordPolicyRuleDto>();

// transformers

public static PasswordPolicyDto fromPasswordPolicyRules(List<PasswordPolicyRule> rules) {
PasswordPolicyDto poilicy = new PasswordPolicyDto();

for (PasswordPolicyRule rule : rules) {
poilicy.rules.add(PasswordPolicyRuleDto.fromRule(rule));
}
return poilicy;
}

// getters / setters

public List<PasswordPolicyRuleDto> getRules() {
return rules;
}

public void setRules(List<PasswordPolicyRuleDto> rules) {
this.rules = rules;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright © 2013-2019 camunda services GmbH and various authors (info@camunda.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.engine.rest.dto.passwordPolicy;

import java.util.Map;

import org.camunda.bpm.engine.pwpolicy.PasswordPolicyRule;

/**
* @author Miklas Boskamp
*/
public class PasswordPolicyRuleDto {
private String placeholder;
private Map<String, String> parameter;

// transformers

public static PasswordPolicyRuleDto fromRule(PasswordPolicyRule rule) {
PasswordPolicyRuleDto dto = new PasswordPolicyRuleDto();
dto.setPlaceholder(rule.getPlaceholder());
dto.setParameter(rule.getParameter());
return dto;
}

// getters / setters

public String getPlaceholder() {
return placeholder;
}

public void setPlaceholder(String placeholder) {
this.placeholder = placeholder;
}

public Map<String, String> getParameter() {
return parameter;
}

public void setParameter(Map<String, String> parameter) {
this.parameter = parameter;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2013-2018 camunda services GmbH and various authors (info@camunda.com)
* Copyright © 2013-2019 camunda services GmbH and various authors (info@camunda.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -104,9 +104,12 @@ public void saveGroup(Group group) {
}

public void saveUser(User user) {

saveUser(user, false);
}

public void saveUser(User user, boolean skipPasswordPolicy) {
try {
commandExecutor.execute(new SaveUserCmd(user));
commandExecutor.execute(new SaveUserCmd(user, skipPasswordPolicy));
} catch (ProcessEngineException ex) {
if (ExceptionUtil.checkConstraintViolationException(ex)) {
throw new BadUserRequestException("The user already exists", ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@
import org.camunda.bpm.engine.impl.persistence.entity.TenantManager;
import org.camunda.bpm.engine.impl.persistence.entity.UserOperationLogManager;
import org.camunda.bpm.engine.impl.persistence.entity.VariableInstanceManager;
import org.camunda.bpm.engine.impl.pwpolicy.DefaultPasswordPolicyImpl;
import org.camunda.bpm.engine.impl.runtime.ConditionHandler;
import org.camunda.bpm.engine.impl.runtime.CorrelationHandler;
import org.camunda.bpm.engine.impl.runtime.DefaultConditionHandler;
Expand Down Expand Up @@ -341,6 +342,7 @@
import org.camunda.bpm.engine.impl.variable.serializer.jpa.EntityManagerSessionFactory;
import org.camunda.bpm.engine.impl.variable.serializer.jpa.JPAVariableSerializer;
import org.camunda.bpm.engine.management.Metrics;
import org.camunda.bpm.engine.pwpolicy.PasswordPolicy;
import org.camunda.bpm.engine.repository.DeploymentBuilder;
import org.camunda.bpm.engine.runtime.Incident;
import org.camunda.bpm.engine.test.mock.MocksResolverFactory;
Expand Down Expand Up @@ -604,6 +606,9 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig

protected SaltGenerator saltGenerator;

protected boolean disablePasswordPolicy;
protected PasswordPolicy passwordPolicy;

protected Set<String> registeredDeployments;

protected ResourceAuthorizationProvider resourceAuthorizationProvider;
Expand Down Expand Up @@ -843,6 +848,7 @@ protected void init() {
initHistoryCleanup();
initAdminUser();
initAdminGroups();
initPasswordPolicy();
invokePostInit();
}

Expand Down Expand Up @@ -2313,9 +2319,13 @@ protected void initPasswordDigest() {
if(passwordManager == null) {
passwordManager = new PasswordManager(passwordEncryptor, customPasswordChecker);
}

}

protected void initPasswordPolicy() {
if(passwordPolicy == null && !disablePasswordPolicy) {
passwordPolicy = new DefaultPasswordPolicyImpl();
}
}

protected void initDeploymentRegistration() {
if (registeredDeployments == null) {
Expand Down Expand Up @@ -2365,7 +2375,7 @@ protected void initAdminGroups() {
adminGroups.add(Groups.CAMUNDA_ADMIN);
}
}

// getters and setters //////////////////////////////////////////////////////

@Override
Expand Down Expand Up @@ -3384,6 +3394,22 @@ public void setPasswordManager(PasswordManager passwordManager) {
this.passwordManager = passwordManager;
}

public PasswordPolicy getPasswordPolicy() {
return passwordPolicy;
}

public void setPasswordPolicy(PasswordPolicy passwordPolicy) {
this.passwordPolicy = passwordPolicy;
}

public boolean isDisablePasswordPolicy() {
return disablePasswordPolicy;
}

public void setDisablePasswordPolicy(boolean disablePasswordPolicy) {
this.disablePasswordPolicy = disablePasswordPolicy;
}

public Set<String> getRegisteredDeployments() {
return registeredDeployments;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2013-2018 camunda services GmbH and various authors (info@camunda.com)
* Copyright © 2013-2019 camunda services GmbH and various authors (info@camunda.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,14 +15,16 @@
*/
package org.camunda.bpm.engine.impl.cmd;

import static org.camunda.bpm.engine.impl.util.EnsureUtil.ensureNotNull;
import static org.camunda.bpm.engine.impl.util.EnsureUtil.ensureWhitelistedResourceId;

import java.io.Serializable;

import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.impl.interceptor.Command;
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.camunda.bpm.engine.impl.persistence.entity.UserEntity;

import static org.camunda.bpm.engine.impl.util.EnsureUtil.ensureNotNull;
import static org.camunda.bpm.engine.impl.util.EnsureUtil.ensureWhitelistedResourceId;
import org.camunda.bpm.engine.pwpolicy.PasswordPolicy;

/**
* @author Joram Barrez
Expand All @@ -31,15 +33,26 @@ public class SaveUserCmd extends AbstractWritableIdentityServiceCmd<Void> implem

private static final long serialVersionUID = 1L;
protected UserEntity user;
private boolean skipPasswordPolicy;

public SaveUserCmd(User user) {
this(user, false);
}

public SaveUserCmd(User user, boolean skipPasswordPolicy) {
this.user = (UserEntity) user;
this.skipPasswordPolicy = skipPasswordPolicy;
}

protected Void executeCmd(CommandContext commandContext) {
ensureNotNull("user", user);
ensureWhitelistedResourceId(commandContext, "User", user.getId());


if(!skipPasswordPolicy && !commandContext.getProcessEngineConfiguration().isDisablePasswordPolicy()) {
PasswordPolicy policy = commandContext.getProcessEngineConfiguration().getPasswordPolicy();
user.checkPasswordAgainstPolicy(policy);
}

commandContext
.getWritableIdentityProvider()
.saveUser(user);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2013-2018 camunda services GmbH and various authors (info@camunda.com)
* Copyright © 2013-2019 camunda services GmbH and various authors (info@camunda.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,6 +23,8 @@
import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.impl.context.Context;
import org.camunda.bpm.engine.impl.db.HasDbRevision;
import org.camunda.bpm.engine.impl.pwpolicy.PasswordPolicyChecker;
import org.camunda.bpm.engine.pwpolicy.PasswordPolicy;
import org.camunda.bpm.engine.impl.db.DbEntity;

import static org.camunda.bpm.engine.impl.util.EncryptionUtil.saltPassword;
Expand Down Expand Up @@ -158,6 +160,11 @@ protected String generateSalt() {
.getSaltGenerator()
.generateSalt();
}


public void checkPasswordAgainstPolicy(PasswordPolicy policy) {
PasswordPolicyChecker.checkPassword(policy, newPassword);
}

public String toString() {
return this.getClass().getSimpleName()
Expand All @@ -172,5 +179,4 @@ public String toString() {
+ ", attempts=" + attempts
+ "]";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright © 2013-2019 camunda services GmbH and various authors (info@camunda.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.engine.impl.pwpolicy;

import java.util.ArrayList;
import java.util.List;

import org.camunda.bpm.engine.pwpolicy.PasswordPolicy;
import org.camunda.bpm.engine.pwpolicy.PasswordPolicyRule;

/**
* @author Miklas Boskamp
*/
public class DefaultPasswordPolicyImpl implements PasswordPolicy {

// password length
public static final int MIN_LENGTH = 10;
// password complexity
public static final int MIN_LOWERCASE = 1;
public static final int MIN_UPPERCSE = 1;
public static final int MIN_DIGIT = 1;
public static final int MIN_SPECIAL = 1;

private final List<PasswordPolicyRule> rules = new ArrayList<PasswordPolicyRule>();

public DefaultPasswordPolicyImpl() {
rules.add(new PasswordPolicyLengthRuleImpl(MIN_LENGTH));
rules.add(new PasswordPolicyLowerCaseRuleImpl(MIN_LOWERCASE));
rules.add(new PasswordPolicyUpperCaseRuleImpl(MIN_UPPERCSE));
rules.add(new PasswordPolicyDigitRuleImpl(MIN_DIGIT));
rules.add(new PasswordPolicySpecialCharacterRuleImpl(MIN_SPECIAL));
}

@Override
public List<PasswordPolicyRule> getRules() {
return this.rules;
}
}
Loading

0 comments on commit 80671e1

Please sign in to comment.