Skip to content

Commit

Permalink
fix issue #542 - web actions do not save/load properly if a basic aut…
Browse files Browse the repository at this point in the history
…h password value isn't included in setting value
  • Loading branch information
jrivard committed Jun 4, 2022
1 parent b9868e9 commit eae0c92
Show file tree
Hide file tree
Showing 3 changed files with 364 additions and 87 deletions.
200 changes: 113 additions & 87 deletions server/src/main/java/password/pwm/config/value/ActionValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import password.pwm.config.stored.StoredConfigXmlSerializer;
import password.pwm.config.stored.XmlOutputProcessData;
import password.pwm.config.value.data.ActionConfiguration;
import password.pwm.error.PwmInternalException;
import password.pwm.error.PwmOperationalException;
import password.pwm.util.java.JavaHelper;
import password.pwm.util.java.JsonUtil;
Expand Down Expand Up @@ -57,7 +58,7 @@ public class ActionValue extends AbstractValue implements StoredValue

public ActionValue( final List<ActionConfiguration> values )
{
this.values = Collections.unmodifiableList( values );
this.values = List.copyOf( JavaHelper.stripNulls( values ) );
}

public static StoredValueFactory factory( )
Expand All @@ -80,10 +81,7 @@ public ActionValue fromJson( final String input )
);

srcList = srcList == null ? Collections.emptyList() : srcList;
while ( srcList.contains( null ) )
{
srcList.remove( null );
}
srcList = JavaHelper.stripNulls( srcList );
return new ActionValue( Collections.unmodifiableList( srcList ) );
}
}
Expand All @@ -97,80 +95,21 @@ public ActionValue fromXmlElement(
throws PwmOperationalException
{
final int syntaxVersion = figureCurrentStoredSyntax( settingElement );
final List<ActionConfiguration> values = new ArrayList<>();

final boolean oldType = PwmSettingSyntax.STRING_ARRAY.toString().equals(
settingElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_SYNTAX ) );
final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );

final List<ActionConfiguration> values = new ArrayList<>( valueElements.size() );
for ( final XmlElement loopValueElement : valueElements )
{
final String stringValue = loopValueElement.getText();
if ( !StringUtil.isEmpty( stringValue ) )
{
if ( syntaxVersion < 2 )
{
if ( oldType )
{
if ( loopValueElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_LOCALE ) == null )
{
final ActionConfiguration.ActionConfigurationOldVersion1 oldVersion1 = ActionConfiguration.ActionConfigurationOldVersion1
.parseOldConfigString( stringValue );
values.add( convertOldVersion1Values( oldVersion1 ) );
}
}
else
{
final ActionConfiguration.ActionConfigurationOldVersion1 parsedAc = JsonUtil
.deserialize( stringValue, ActionConfiguration.ActionConfigurationOldVersion1.class );
if ( parsedAc != null )
{
final Optional<String> decodedValue = StoredValueEncoder.decode(
parsedAc.getPassword(),
StoredValueEncoder.Mode.ENCODED,
pwmSecurityKey );
decodedValue.ifPresent( s ->
{
values.add( convertOldVersion1Values( parsedAc.toBuilder().password( s ).build() ) );
} );
}
}
parseV1configurationValue( pwmSecurityKey, loopValueElement, stringValue ).ifPresent( values::add );
}
else if ( syntaxVersion == 2 )
{
final ActionConfiguration value = JsonUtil.deserialize( stringValue, ActionConfiguration.class );
final List<ActionConfiguration.WebAction> clonedWebActions = new ArrayList<>();
for ( final ActionConfiguration.WebAction webAction : value.getWebActions() )
{
// add success status if empty list
final List<Integer> successStatus = JavaHelper.isEmpty( webAction.getSuccessStatus() )
? Collections.singletonList( 200 )
: webAction.getSuccessStatus();

// decrypt pw
try
{


final Optional<String> decodedValue = StoredValueEncoder.decode(
webAction.getPassword(),
StoredValueEncoder.Mode.ENCODED,
pwmSecurityKey );
decodedValue.ifPresent( s ->
{
clonedWebActions.add( webAction.toBuilder()
.password( s )
.successStatus( successStatus )
.build() );
} );
}
catch ( final PwmOperationalException e )
{
LOGGER.warn( () -> "error decoding stored pw value on setting '" + pwmSetting.getKey() + "': " + e.getMessage() );
}
}

final ActionConfiguration clonedAction = value.toBuilder().webActions( clonedWebActions ).build();
values.add( clonedAction );
parseV2configurationValue( pwmSetting, pwmSecurityKey, stringValue ).ifPresent( values::add );
}
else
{
Expand All @@ -181,39 +120,97 @@ else if ( syntaxVersion == 2 )

return new ActionValue( values );
}
};
}

@Override
public List<XmlElement> toXmlValues( final String valueElementName, final XmlOutputProcessData xmlOutputProcessData )
{
final List<XmlElement> returnList = new ArrayList<>();
for ( final ActionConfiguration value : values )
{
final List<ActionConfiguration.WebAction> clonedWebActions = new ArrayList<>();
for ( final ActionConfiguration.WebAction webAction : value.getWebActions() )
private Optional<ActionConfiguration> parseV1configurationValue(
final PwmSecurityKey pwmSecurityKey,
final XmlElement loopValueElement,
final String stringValue
)
throws PwmOperationalException
{
final XmlElement settingElement = loopValueElement.parent();
final boolean oldType = PwmSettingSyntax.STRING_ARRAY.toString().equals(
settingElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_SYNTAX ) );

if ( oldType )
{
if ( loopValueElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_LOCALE ).isEmpty() )
{
final ActionConfiguration.ActionConfigurationOldVersion1 oldVersion1 = ActionConfiguration.ActionConfigurationOldVersion1
.parseOldConfigString( stringValue );
return Optional.of( convertOldVersion1Values( oldVersion1 ) );
}
}
else
{
final ActionConfiguration.ActionConfigurationOldVersion1 parsedAc = JsonUtil
.deserialize( stringValue, ActionConfiguration.ActionConfigurationOldVersion1.class );
if ( parsedAc != null )
{
final Optional<String> decodedValue = StoredValueEncoder.decode(
parsedAc.getPassword(),
StoredValueEncoder.Mode.ENCODED,
pwmSecurityKey );

if ( decodedValue.isPresent() )
{
return Optional.of( convertOldVersion1Values( parsedAc.toBuilder().password( decodedValue.get() ).build() ) );
}
}
}

return Optional.empty();
}

private Optional<ActionConfiguration> parseV2configurationValue( final PwmSetting pwmSetting, final PwmSecurityKey pwmSecurityKey, final String stringValue )
{
if ( !StringUtil.isEmpty( webAction.getPassword() ) )
final ActionConfiguration value = JsonUtil.deserialize( stringValue, ActionConfiguration.class );
final List<ActionConfiguration.WebAction> clonedWebActions = new ArrayList<>( value.getWebActions().size() );

for ( final ActionConfiguration.WebAction webAction : value.getWebActions() )
{
// add success status if empty list
final List<Integer> successStatus = JavaHelper.isEmpty( webAction.getSuccessStatus() )
? Collections.singletonList( 200 )
: webAction.getSuccessStatus();

// decrypt pw
Optional<String> decodedValue = Optional.empty();
try
{
final String encodedValue = StoredValueEncoder.encode(
decodedValue = StoredValueEncoder.decode(
webAction.getPassword(),
xmlOutputProcessData.getStoredValueEncoderMode(),
xmlOutputProcessData.getPwmSecurityKey() );
clonedWebActions.add( webAction.toBuilder()
.password( encodedValue )
.build() );
StoredValueEncoder.Mode.ENCODED,
pwmSecurityKey );
}
catch ( final PwmOperationalException e )
{
LOGGER.warn( () -> "error encoding stored pw value: " + e.getMessage() );
LOGGER.warn( () -> "error decoding stored pw value on setting '" + pwmSetting.getKey() + "': " + e.getMessage() );
}

final String passwordValue = decodedValue.orElse( "" );
clonedWebActions.add( webAction.toBuilder()
.password( passwordValue )
.successStatus( successStatus )
.build() );
}

return Optional.of( value.toBuilder().webActions( clonedWebActions ).build() );
}
};
}

final ActionConfiguration clonedAction = value.toBuilder().webActions( clonedWebActions ).build();
@Override
public List<XmlElement> toXmlValues( final String valueElementName, final XmlOutputProcessData xmlOutputProcessData )
{
final List<XmlElement> returnList = new ArrayList<>( values.size() );
for ( final ActionConfiguration value : values )
{
final List<ActionConfiguration.WebAction> clonedWebActions = encodePasswordInWebActions( value.getWebActions(), xmlOutputProcessData );

final ActionConfiguration clonedAction = value.toBuilder()
.webActions( clonedWebActions )
.build();

final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );

Expand All @@ -223,6 +220,35 @@ public List<XmlElement> toXmlValues( final String valueElementName, final XmlOut
return returnList;
}

private static List<ActionConfiguration.WebAction> encodePasswordInWebActions(
final List<ActionConfiguration.WebAction> webActions,
final XmlOutputProcessData xmlOutputProcessData
)
{
final List<ActionConfiguration.WebAction> clonedWebActions = new ArrayList<>( webActions.size() );

for ( final ActionConfiguration.WebAction webAction : webActions )
{
try
{
final String encodedValue = StringUtil.isEmpty( webAction.getPassword() )
? ""
: StoredValueEncoder.encode( webAction.getPassword(),
xmlOutputProcessData.getStoredValueEncoderMode(),
xmlOutputProcessData.getPwmSecurityKey() );
clonedWebActions.add( webAction.toBuilder()
.password( encodedValue )
.build() );
}
catch ( final PwmOperationalException e )
{
throw new PwmInternalException( "error encoding stored pw value: " + e.getMessage(), e );
}
}
return Collections.unmodifiableList( clonedWebActions );
}


@Override
public List<ActionConfiguration> toNativeObject( )
{
Expand Down
Loading

0 comments on commit eae0c92

Please sign in to comment.