On 5/25/2016 10:34 PM, Endi Sukma Dewata wrote:
The TPSSubsystem has been modified to load and validate the token
state transition lists during initialization. If any of the lists
is empty or any of the transitions is invalid, the initialization
will fail and the subsystem will not start.
https://fedorahosted.org/pki/ticket/2334
Rebased.
--
Endi S. Dewata
>From 68dc8284942c22f9d4e798d098edc966798b3d8e Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <[email protected]>
Date: Wed, 25 May 2016 06:27:46 +0200
Subject: [PATCH] Added TPS token state transition validation.
The TPSSubsystem has been modified to load and validate the token
state transition lists during initialization. If any of the lists
is empty or any of the transitions is invalid, the initialization
will fail and the subsystem will not start.
https://fedorahosted.org/pki/ticket/2334
---
.../src/org/dogtagpki/server/tps/TPSSubsystem.java | 124 +++++++++++++++++----
.../src/org/dogtagpki/server/tps/TPSTokendb.java | 2 +-
.../org/dogtagpki/server/tps/engine/TPSEngine.java | 51 ---------
.../server/tps/processor/TPSEnrollProcessor.java | 3 +-
.../server/tps/processor/TPSProcessor.java | 7 +-
.../dogtagpki/server/tps/rest/TokenService.java | 17 ++-
6 files changed, 122 insertions(+), 82 deletions(-)
diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java b/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java
index 2d415c16c7da0b4ad19ecc7d4b2ac3e2d329aa70..7146eb4cfe0b3a1f48743c807db9f03b3c4b63a9 100644
--- a/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java
@@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
+import org.apache.commons.lang.StringUtils;
import org.dogtagpki.server.tps.authentication.AuthenticationManager;
import org.dogtagpki.server.tps.cms.ConnectionManager;
import org.dogtagpki.server.tps.config.AuthenticatorDatabase;
@@ -36,6 +37,7 @@ import org.dogtagpki.server.tps.dbs.TokenDatabase;
import org.dogtagpki.server.tps.dbs.TokenRecord;
import org.dogtagpki.server.tps.engine.TPSEngine;
import org.dogtagpki.server.tps.mapping.MappingResolverManager;
+import org.dogtagpki.tps.main.TPSException;
import org.mozilla.jss.CryptoManager;
import org.mozilla.jss.CryptoManager.NotInitializedException;
import org.mozilla.jss.crypto.ObjectNotFoundException;
@@ -51,6 +53,7 @@ import com.netscape.certsrv.logging.ILogger;
import com.netscape.certsrv.request.IRequestListener;
import com.netscape.certsrv.request.IRequestQueue;
import com.netscape.certsrv.tps.token.TokenStatus;
+import com.netscape.cmscore.base.FileConfigStore;
import com.netscape.cmscore.dbs.DBSubsystem;
/**
@@ -81,7 +84,9 @@ public class TPSSubsystem implements IAuthority, ISubsystem {
public TPSEngine engine;
public TPSTokendb tdb;
- public Map<TokenStatus, Collection<TokenStatus>> allowedTransitions = new HashMap<TokenStatus, Collection<TokenStatus>>();
+
+ public Map<TokenStatus, Collection<TokenStatus>> uiTransitions;
+ public Map<TokenStatus, Collection<TokenStatus>> operationTransitions;
@Override
public String getId() {
@@ -116,45 +121,109 @@ public class TPSSubsystem implements IAuthority, ISubsystem {
profileDatabase = new ProfileDatabase();
profileMappingDatabase = new ProfileMappingDatabase();
- CMS.debug("TokenSubsystem: allowed transitions:");
+ FileConfigStore defaultConfig = new FileConfigStore("/usr/share/pki/tps/conf/CS.cfg");
- // initialize allowed token state transitions with empty containers
- for (TokenStatus state : TokenStatus.values()) {
- allowedTransitions.put(state, new LinkedHashSet<TokenStatus>());
- }
+ uiTransitions = loadAndValidateTokenStateTransitions(
+ defaultConfig, cs, TPSEngine.CFG_TOKENDB_ALLOWED_TRANSITIONS);
- // load allowed token state transitions from TPS configuration
- for (String transition : cs.getString(TPSEngine.CFG_TOKENDB_ALLOWED_TRANSITIONS).split(",")) {
- String states[] = transition.split(":");
-
- TokenStatus fromState = TokenStatus.fromInt(Integer.valueOf(states[0]));
- TokenStatus toState = TokenStatus.fromInt(Integer.valueOf(states[1]));
- CMS.debug("TokenSubsystem: - " + fromState + " to " + toState);
-
- Collection<TokenStatus> nextStates = allowedTransitions.get(fromState);
- nextStates.add(toState);
- }
+ operationTransitions = loadAndValidateTokenStateTransitions(
+ defaultConfig, cs, TPSEngine.CFG_OPERATIONS_ALLOWED_TRANSITIONS);
tdb = new TPSTokendb(this);
engine = new TPSEngine();
engine.init();
+ }
+
+ public Map<TokenStatus, Collection<TokenStatus>> loadTokenStateTransitions(IConfigStore cs, String property) throws EBaseException {
+
+ String value = cs.getString(property);
+
+ if (StringUtils.isEmpty(value)) {
+ CMS.debug("Missing token state transitions in " + property);
+ throw new EBaseException("Missing token state transition in " + property);
+ }
+
+ Map<TokenStatus, Collection<TokenStatus>> transitions = new HashMap<TokenStatus, Collection<TokenStatus>>();
+
+ // initialize list with empty containers
+ for (TokenStatus state : TokenStatus.values()) {
+ transitions.put(state, new LinkedHashSet<TokenStatus>());
+ }
+
+ for (String transition : value.split(",")) {
+
+ String states[] = transition.split(":");
+ if (states.length < 2) {
+ CMS.debug("Invalid token state transition in " + property + ": " + transition);
+ throw new EBaseException("Invalid token state transition in " + property + ": " + transition);
+ }
+
+ TokenStatus currentState = TokenStatus.fromInt(Integer.valueOf(states[0]));
+ TokenStatus nextState = TokenStatus.fromInt(Integer.valueOf(states[1]));
+
+ String info = currentState + " to " + nextState +
+ " (" + currentState.getValue() + ":" + nextState.getValue() + ")";
+ CMS.debug("TokenSubsystem: - " + info);
+
+ Collection<TokenStatus> nextStates = transitions.get(currentState);
+ nextStates.add(nextState);
+ }
+ return transitions;
}
+ public void validateTokenStateTransitions(
+ Map<TokenStatus, Collection<TokenStatus>> defaultConfig,
+ Map<TokenStatus, Collection<TokenStatus>> userConfig) throws EBaseException {
+
+ for (TokenStatus currentState : userConfig.keySet()) {
+ Collection<TokenStatus> nextStates = userConfig.get(currentState);
+ Collection<TokenStatus> defaultNextStates = defaultConfig.get(currentState);
+
+ for (TokenStatus nextState : nextStates) {
+ if (!defaultNextStates.contains(nextState)) {
+ String info = currentState + " to " + nextState +
+ " (" + currentState.getValue() + ":" + nextState.getValue() + ")";
+ throw new EBaseException("Unsupported token state transition: " + info);
+ }
+ }
+ }
+ }
+
+ public Map<TokenStatus, Collection<TokenStatus>> loadAndValidateTokenStateTransitions(
+ IConfigStore defaultConfig,
+ IConfigStore userDefinedConfig,
+ String property) throws EBaseException {
+
+ CMS.debug("TokenSubsystem: Loading transitions in " + property);
+
+ CMS.debug("TokenSubsystem: * default transitions:");
+ Map<TokenStatus, Collection<TokenStatus>> defaultTransitions =
+ loadTokenStateTransitions(defaultConfig, property);
+
+ CMS.debug("TokenSubsystem: * user-defined transitions:");
+ Map<TokenStatus, Collection<TokenStatus>> userDefinedTransitions =
+ loadTokenStateTransitions(userDefinedConfig, property);
+
+ CMS.debug("TokenSubsystem: Validating transitions in " + property);
+ validateTokenStateTransitions(defaultTransitions, userDefinedTransitions);
+
+ return userDefinedTransitions;
+ }
/**
- * Return the allowed next states for a given token based on TPS configuration.
+ * Return the allowed next states for changing token state via Web UI or CLI.
*
- * If the current state is SUSPENDED, token will be allowed transition to either
- * FORMATTED or ACTIVE depending on whether the token has certificates.
+ * If the current state is SUSPENDED, token will be allowed to transition to
+ * either FORMATTED or ACTIVE depending on whether the token has certificates.
*
* @param tokenRecord
* @return A non-null collection of allowed next token states.
*/
- public Collection<TokenStatus> getNextTokenStates(TokenRecord tokenRecord) throws Exception {
+ public Collection<TokenStatus> getUINextTokenStates(TokenRecord tokenRecord) throws TPSException {
TokenStatus currentState = tokenRecord.getTokenStatus();
- Collection<TokenStatus> nextStates = allowedTransitions.get(currentState);
+ Collection<TokenStatus> nextStates = uiTransitions.get(currentState);
if (currentState == TokenStatus.SUSPENDED) {
@@ -180,6 +249,17 @@ public class TPSSubsystem implements IAuthority, ISubsystem {
return nextStates;
}
+ /**
+ * Return the allowed next states for TPS token operations (i.e. format and enrollment).
+ *
+ * @param tokenRecord
+ * @return A non-null collection of allowed next token states.
+ */
+ public Collection<TokenStatus> getOperationNextTokenStates(TokenRecord tokenRecord) throws TPSException {
+ TokenStatus currentState = tokenRecord.getTokenStatus();
+ return operationTransitions.get(currentState);
+ }
+
@Override
public void startup() throws EBaseException {
CMS.debug("TPSSubsystem: startup() begins");
diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java
index 7997cc579687658de93b8040aabe7ade15465ae2..ed7e022faf7d85bee8e53ebe37b35a16b713bde5 100644
--- a/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java
@@ -64,7 +64,7 @@ public class TPSTokendb {
TokenStatus currentTokenStatus = tokenRecord.getTokenStatus();
CMS.debug("TokenRecord.isTransitionAllowed(): current status: " + currentTokenStatus);
- Collection<TokenStatus> nextStatuses = tps.getNextTokenStates(tokenRecord);
+ Collection<TokenStatus> nextStatuses = tps.getUINextTokenStates(tokenRecord);
CMS.debug("TokenRecord.isTransitionAllowed(): allowed next statuses: " + nextStatuses);
if (!nextStatuses.contains(newState)) {
diff --git a/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java b/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java
index a577a76199a51e37f8bbcd7b7477f39aad85c8e8..a5fbc3b7dfe4d55262baccb0ebfbf05077acbd1f 100644
--- a/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java
+++ b/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java
@@ -37,8 +37,6 @@ import org.dogtagpki.tps.msg.EndOpMsg.TPSStatus;
import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.base.EBaseException;
-import com.netscape.certsrv.base.IConfigStore;
-import com.netscape.certsrv.tps.token.TokenStatus;
public class TPSEngine {
@@ -195,8 +193,6 @@ public class TPSEngine {
public static final String ENROLL_MODE_RECOVERY = RECOVERY_OP;
public static final String ERNOLL_MODE_RENEWAL = RENEWAL_OP;
- private static String transitionList;
-
public void init() {
//ToDo
}
@@ -589,51 +585,4 @@ public class TPSEngine {
return resp;
}
-
- //Check to see if special operations transition is allowed
-
- public boolean isOperationTransitionAllowed(TokenStatus oldState, TokenStatus newState) throws TPSException {
- boolean allowed = true;
-
- if (transitionList == null) {
-
- IConfigStore configStore = CMS.getConfigStore();
-
- String transConfig = CFG_OPERATIONS_ALLOWED_TRANSITIONS;
-
- CMS.debug("TPSEngine.isOperationTransistionAllowed: getting config: " + transConfig);
- try {
- transitionList = configStore.getString(transConfig, null);
- } catch (EBaseException e) {
- throw new TPSException(
- "TPSProcessor.isOperationTransitionAllowed: Internal error getting config value for operations transition list!",
- TPSStatus.STATUS_ERROR_MISCONFIGURATION);
- }
-
- if (transitionList == null) {
- throw new TPSException(
- "TPSProcessor.isOperationTransitionAllowed: Can't find non null config value for operations transition list!",
- TPSStatus.STATUS_ERROR_MISCONFIGURATION);
- }
-
- CMS.debug("TPSEngine.isOperationTransistionAllowed: transitionList is: " + transitionList);
-
- }
-
- String transition = oldState.getValue() + ":" + newState.getValue();
-
- CMS.debug("TPSEngine.isOperationTransistionAllowed: checking for transition: " + transition);
-
- if (transitionList.indexOf(transition) == -1) {
- CMS.debug("TPSEngine.isOperationTransistionAllowed: checking for transition: " + transition);
- allowed = false;
- }
-
- CMS.debug("TPSEngine.isOperationTransistionAllowed: checking for transition: " + transition + " allowed: "
- + allowed);
-
- return allowed;
-
- }
-
}
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
index bbdc15b86456077a5ff7c64c0b8d79b281fa098c..5f29381c586807efad8454524e58d90cd90265a5 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
@@ -282,7 +282,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
TokenStatus newState = TokenStatus.ACTIVE;
// Check for transition to ACTIVE status.
- if (!tps.engine.isOperationTransitionAllowed(tokenRecord.getTokenStatus(), newState)) {
+ Collection<TokenStatus> nextStates = tps.getOperationNextTokenStates(tokenRecord);
+ if (!nextStates.contains(newState)) {
CMS.debug(method + " token transition disallowed " +
tokenRecord.getTokenStatus() +
" to " + newState);
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
index aa2f24260d813bac423af0e1d5015402a38bb51c..0946328f3503e994da9a000159e0d39d192e816e 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
@@ -33,8 +33,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import netscape.security.x509.RevocationReason;
-
import org.dogtagpki.server.tps.TPSSession;
import org.dogtagpki.server.tps.TPSSubsystem;
import org.dogtagpki.server.tps.authentication.AuthUIParameter;
@@ -98,6 +96,8 @@ import com.netscape.certsrv.tps.token.TokenStatus;
import com.netscape.cms.servlet.tks.SecureChannelProtocol;
import com.netscape.symkey.SessionKey;
+import netscape.security.x509.RevocationReason;
+
public class TPSProcessor {
public static final int RESULT_NO_ERROR = 0;
@@ -2088,7 +2088,8 @@ public class TPSProcessor {
TokenStatus newState = TokenStatus.FORMATTED;
// Check for transition to FORMATTED status.
- if (!tps.engine.isOperationTransitionAllowed(tokenRecord.getTokenStatus(), newState)) {
+ Collection<TokenStatus> nextStates = tps.getOperationNextTokenStates(tokenRecord);
+ if (!nextStates.contains(newState)) {
String info = " illegal transition attempted: " + tokenRecord.getTokenStatus() +
" to " + newState;
CMS.debug("TPSProcessor.format: token transition: " + info);
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/TokenService.java b/base/tps/src/org/dogtagpki/server/tps/rest/TokenService.java
index 40022a44044169afc2bc15b000026e57ea995d3e..0faf50c119b2c8f53db4951351e7824149bab232 100644
--- a/base/tps/src/org/dogtagpki/server/tps/rest/TokenService.java
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/TokenService.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.servlet.http.HttpServletRequest;
@@ -185,15 +186,23 @@ public class TokenService extends PKIService implements TokenResource {
TokenStatus status = tokenRecord.getTokenStatus();
TokenStatusData statusData = new TokenStatusData();
statusData.name = status;
- statusData.label = labels.getString(status.toString());
+ try {
+ statusData.label = labels.getString(status.toString());
+ } catch (MissingResourceException e) {
+ statusData.label = status.toString();
+ }
tokenData.setStatus(statusData);
- Collection<TokenStatus> nextStates = subsystem.getNextTokenStates(tokenRecord);
+ Collection<TokenStatus> nextStates = subsystem.getUINextTokenStates(tokenRecord);
Collection<TokenStatusData> nextStatesData = new ArrayList<TokenStatusData>();
for (TokenStatus nextState : nextStates) {
TokenStatusData nextStateData = new TokenStatusData();
nextStateData.name = nextState;
- nextStateData.label = labels.getString(status + "." + nextState);
+ try {
+ nextStateData.label = labels.getString(status + "." + nextState);
+ } catch (MissingResourceException e) {
+ nextStateData.label = nextState.toString();
+ }
nextStatesData.add(nextStateData);
}
tokenData.setNextStates(nextStatesData);
@@ -646,7 +655,7 @@ public class TokenService extends PKIService implements TokenResource {
msg = msg + " from " + currentTokenStatus + " to " + tokenStatus;
// make sure transition is allowed
- Collection<TokenStatus> nextStatuses = subsystem.getNextTokenStates(tokenRecord);
+ Collection<TokenStatus> nextStatuses = subsystem.getUINextTokenStates(tokenRecord);
CMS.debug("TokenService.changeTokenStatus(): allowed next statuses: " + nextStatuses);
if (!nextStatuses.contains(tokenStatus)) {
--
2.5.5
_______________________________________________
Pki-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/pki-devel