SecretsManager.java

1
/**
2
   Copyright 2018 Carlos Macasaet
3
4
   Licensed under the Apache License, Version 2.0 (the "License");
5
   you may not use this file except in compliance with the License.
6
   You may obtain a copy of the License at
7
8
       https://www.apache.org/licenses/LICENSE-2.0
9
10
   Unless required by applicable law or agreed to in writing, software
11
   distributed under the License is distributed on an "AS IS" BASIS,
12
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
   See the License for the specific language governing permissions and
14
   limitations under the License.
15
 */
16
package com.macasaet.fernet.aws.secretsmanager.rotation;
17
18
import static com.macasaet.fernet.aws.secretsmanager.rotation.Stage.CURRENT;
19
import static java.util.Collections.singletonList;
20
21
import java.io.ByteArrayOutputStream;
22
import java.io.IOException;
23
import java.nio.ByteBuffer;
24
import java.util.Collection;
25
26
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
27
import com.amazonaws.services.secretsmanager.model.DescribeSecretRequest;
28
import com.amazonaws.services.secretsmanager.model.DescribeSecretResult;
29
import com.amazonaws.services.secretsmanager.model.GetSecretValueRequest;
30
import com.amazonaws.services.secretsmanager.model.GetSecretValueResult;
31
import com.amazonaws.services.secretsmanager.model.PutSecretValueRequest;
32
import com.amazonaws.services.secretsmanager.model.ResourceNotFoundException;
33
import com.amazonaws.services.secretsmanager.model.UpdateSecretVersionStageRequest;
34
import com.macasaet.fernet.Key;
35
36
/**
37
 * <p>Service façade for AWS Secrets Manager.</p>
38
 *
39
 * <p>This requires the following permissions: <code>secretsmanager:DescribeSecret</code>,
40
 * <code>secretsmanager:GetSecretValue</code>, <code>secretsmanager:UpdateSecretVersionStage</code>, and
41
 * <code>secretsmanager:PutSecretValue</code>.</p>
42
 * <p>Copyright &copy; 2018 Carlos Macasaet.</p>
43
 *
44
 * @author Carlos Macasaet
45
 */
46
@SuppressWarnings("PMD.LawOfDemeter")
47
class SecretsManager {
48
49
    private final AWSSecretsManager delegate;
50
51
    public SecretsManager(final AWSSecretsManager delegate) {
52 1 1. <init> : negated conditional → KILLED
        if (delegate == null) {
53
            throw new IllegalArgumentException("delegate cannot be null");
54
        }
55
        this.delegate = delegate;
56
    }
57
58
    public void shutdown() {
59 1 1. shutdown : removed call to com/amazonaws/services/secretsmanager/AWSSecretsManager::shutdown → NO_COVERAGE
        getDelegate().shutdown();
60
    }
61
62
    /**
63
     * Ensure that the given secret has an AWSCURRENT value. This requires the permission
64
     * <code>secretsmanager:GetSecretValue</code>
65
     *
66
     * @param secretId
67
     *            the ARN of the secret.
68
     * @throws ResourceNotFoundException if the secret doesn't exist or it has no AWSCURRENT stage
69
     */
70
    public void assertCurrentStageExists(final String secretId) {
71
        final GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest();
72 1 1. assertCurrentStageExists : removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setSecretId → KILLED
        getSecretValueRequest.setSecretId(secretId);
73 1 1. assertCurrentStageExists : removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setVersionStage → KILLED
        getSecretValueRequest.setVersionStage(CURRENT.getAwsName());
74
        getDelegate().getSecretValue(getSecretValueRequest);
75
    }
76
77
    /**
78
     * Obtain a secret's metadata. This requires the permission <code>secretsmanager:DescribeSecret</code>
79
     *
80
     * @param secretId the ARN of the secret
81
     * @return the secret's metadata
82
     */
83
    public DescribeSecretResult describeSecret(final String secretId) {
84
        final DescribeSecretRequest describeSecretRequest = new DescribeSecretRequest();
85 1 1. describeSecret : removed call to com/amazonaws/services/secretsmanager/model/DescribeSecretRequest::setSecretId → KILLED
        describeSecretRequest.setSecretId(secretId);
86 1 1. describeSecret : mutated return of Object value for com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::describeSecret to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return getDelegate().describeSecret(describeSecretRequest);
87
    }
88
89
    /**
90
     * Retrieve a specific version of the secret. This requires the permission <code>secretsmanager:GetSecretValue</code>
91
     *
92
     * @param secretId the ARN of the secret
93
     * @param clientRequestToken the version identifier of the secret
94
     * @return the Fernet key or keys in binary form
95
     */
96
    public ByteBuffer getSecretVersion(final String secretId, final String clientRequestToken) {
97
        final GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest();
98 1 1. getSecretVersion : removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setSecretId → KILLED
        getSecretValueRequest.setSecretId(secretId);
99 1 1. getSecretVersion : removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setVersionId → KILLED
        getSecretValueRequest.setVersionId(clientRequestToken);
100
        final GetSecretValueResult result = getDelegate().getSecretValue(getSecretValueRequest);
101 1 1. getSecretVersion : mutated return of Object value for com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::getSecretVersion to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return result.getSecretBinary();
102
    }
103
104
    /**
105
     * Retrieve a specific stage of the secret.
106
     *
107
     * @param secretId the ARN of the secret
108
     * @param stage the stage of the secret to retrieve
109
     * @return the Fernet key or keys in binary form
110
     */
111
    public ByteBuffer getSecretStage(final String secretId, final Stage stage) {
112
        final GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest();
113 1 1. getSecretStage : removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setSecretId → KILLED
        getSecretValueRequest.setSecretId(secretId);
114 1 1. getSecretStage : removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setVersionStage → KILLED
        getSecretValueRequest.setVersionStage(stage.getAwsName());
115
        final GetSecretValueResult result = getDelegate().getSecretValue(getSecretValueRequest);
116 1 1. getSecretStage : mutated return of Object value for com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::getSecretStage to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return result.getSecretBinary();
117
    }
118
119
    /**
120
     * Rotate a secret. This requires the permission <code>secretsmanager:UpdateSecretVersionStage</code>
121
     *
122
     * @param secretId
123
     *            the ARN of the secret
124
     * @param clientRequestToken
125
     *            the version ID to be made "current"
126
     * @param currentVersion
127
     *            the current active version ID to be made "previous"
128
     */
129
    public void rotateSecret(final String secretId, final String clientRequestToken,
130
            final String currentVersion) {
131
        final UpdateSecretVersionStageRequest updateSecretVersionStageRequest = new UpdateSecretVersionStageRequest();
132 1 1. rotateSecret : removed call to com/amazonaws/services/secretsmanager/model/UpdateSecretVersionStageRequest::setSecretId → KILLED
        updateSecretVersionStageRequest.setSecretId(secretId);
133 1 1. rotateSecret : removed call to com/amazonaws/services/secretsmanager/model/UpdateSecretVersionStageRequest::setVersionStage → KILLED
        updateSecretVersionStageRequest.setVersionStage(CURRENT.getAwsName());
134 1 1. rotateSecret : removed call to com/amazonaws/services/secretsmanager/model/UpdateSecretVersionStageRequest::setMoveToVersionId → KILLED
        updateSecretVersionStageRequest.setMoveToVersionId(clientRequestToken);
135 1 1. rotateSecret : removed call to com/amazonaws/services/secretsmanager/model/UpdateSecretVersionStageRequest::setRemoveFromVersionId → KILLED
        updateSecretVersionStageRequest.setRemoveFromVersionId(currentVersion);
136
        getDelegate().updateSecretVersionStage(updateSecretVersionStageRequest);
137
    }
138
139
    /**
140
     * Store a single Fernet key in a secret. This requires the permission <code>secretsmanager:PutSecretValue</code>
141
     *
142
     * @param secretId
143
     *            the ARN of the secret
144
     * @param clientRequestToken
145
     *            the secret version identifier
146
     * @param key
147
     *            the key to store in the secret
148
     * @param stage
149
     *            the stage with which to tag the version
150
     */
151
    public void putSecretValue(final String secretId, final String clientRequestToken, final Key key, final Stage stage) {
152 1 1. putSecretValue : removed call to com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::putSecretValue → KILLED
        putSecretValue(secretId, clientRequestToken, singletonList(key), stage);
153
    }
154
155
    /**
156
     * Store Fernet keys in the secret. This requires the permission <code>secretsmanager:PutSecretValue</code>
157
     *
158
     * @param secretId
159
     *            the ARN of the secret
160
     * @param clientRequestToken
161
     *            the secret version identifier
162
     * @param keys
163
     *            the keys to store in the secret
164
     * @param stage
165
     *            the stage with which to tag the version
166
     */
167
    public void putSecretValue(final String secretId, final String clientRequestToken, final Collection<? extends Key> keys,
168
            final Stage stage) {
169
        final PutSecretValueRequest putSecretValueRequest = new PutSecretValueRequest();
170 1 1. putSecretValue : removed call to com/amazonaws/services/secretsmanager/model/PutSecretValueRequest::setSecretId → KILLED
        putSecretValueRequest.setSecretId(secretId);
171 1 1. putSecretValue : removed call to com/amazonaws/services/secretsmanager/model/PutSecretValueRequest::setClientRequestToken → KILLED
        putSecretValueRequest.setClientRequestToken(clientRequestToken);
172 1 1. putSecretValue : removed call to com/amazonaws/services/secretsmanager/model/PutSecretValueRequest::setVersionStages → KILLED
        putSecretValueRequest.setVersionStages(singletonList(stage.getAwsName()));
173 3 1. putSecretValue : Replaced integer multiplication with division → SURVIVED
2. putSecretValue : removed call to java/io/ByteArrayOutputStream::close → NO_COVERAGE
3. putSecretValue : removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(32 * keys.size())) {
174
            for (final Key key : keys) {
175 1 1. putSecretValue : removed call to com/macasaet/fernet/Key::writeTo → KILLED
                key.writeTo(outputStream);
176
            }
177
            final ByteBuffer buffer = ByteBuffer.wrap(outputStream.toByteArray());
178 1 1. putSecretValue : removed call to com/amazonaws/services/secretsmanager/model/PutSecretValueRequest::setSecretBinary → KILLED
            putSecretValueRequest.setSecretBinary(buffer);
179
            
180 1 1. putSecretValue : removed call to java/io/ByteArrayOutputStream::reset → SURVIVED
            outputStream.reset();
181 4 1. putSecretValue : changed conditional boundary → SURVIVED
2. putSecretValue : negated conditional → SURVIVED
3. putSecretValue : removed call to java/io/ByteArrayOutputStream::write → SURVIVED
4. putSecretValue : Changed increment from -1 to 1 → KILLED
            for (int i = keys.size(); --i >= 0; outputStream.write(0));
182 1 1. putSecretValue : removed call to java/io/ByteArrayOutputStream::close → SURVIVED
        } catch (final IOException ioe) {
183
            // this really should not happen as I/O is to memory only
184
            throw new IllegalStateException(ioe.getMessage(), ioe);
185
        }
186
187
        getDelegate().putSecretValue(putSecretValueRequest);
188
    }
189
190
    protected AWSSecretsManager getDelegate() {
191 1 1. getDelegate : mutated return of Object value for com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::getDelegate to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return delegate;
192
    }
193
194
}

Mutations

52

1.1
Location : <init>
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyAssertDoesNothing(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
negated conditional → KILLED

59

1.1
Location : shutdown
Killed by : none
removed call to com/amazonaws/services/secretsmanager/AWSSecretsManager::shutdown → NO_COVERAGE

72

1.1
Location : assertCurrentStageExists
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyAssertCurrentStageExistsThrowsException(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setSecretId → KILLED

73

1.1
Location : assertCurrentStageExists
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyAssertCurrentStageExistsThrowsException(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setVersionStage → KILLED

85

1.1
Location : describeSecret
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyDescribeSecretPassesThrough(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/DescribeSecretRequest::setSecretId → KILLED

86

1.1
Location : describeSecret
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyDescribeSecretPassesThrough(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
mutated return of Object value for com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::describeSecret to ( if (x != null) null else throw new RuntimeException ) → KILLED

98

1.1
Location : getSecretVersion
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyGetSecretVersionRetrievesBinary(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setSecretId → KILLED

99

1.1
Location : getSecretVersion
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyGetSecretVersionRetrievesBinary(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setVersionId → KILLED

101

1.1
Location : getSecretVersion
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyGetSecretVersionRetrievesBinary(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
mutated return of Object value for com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::getSecretVersion to ( if (x != null) null else throw new RuntimeException ) → KILLED

113

1.1
Location : getSecretStage
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyGetSecretStageRetrievesBinary(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setSecretId → KILLED

114

1.1
Location : getSecretStage
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyGetSecretStageRetrievesBinary(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/GetSecretValueRequest::setVersionStage → KILLED

116

1.1
Location : getSecretStage
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyGetSecretStageRetrievesBinary(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
mutated return of Object value for com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::getSecretStage to ( if (x != null) null else throw new RuntimeException ) → KILLED

132

1.1
Location : rotateSecret
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyRotateSecretTagsNewKeyAndUntagsOldKey(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/UpdateSecretVersionStageRequest::setSecretId → KILLED

133

1.1
Location : rotateSecret
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyRotateSecretTagsNewKeyAndUntagsOldKey(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/UpdateSecretVersionStageRequest::setVersionStage → KILLED

134

1.1
Location : rotateSecret
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyRotateSecretTagsNewKeyAndUntagsOldKey(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/UpdateSecretVersionStageRequest::setMoveToVersionId → KILLED

135

1.1
Location : rotateSecret
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyRotateSecretTagsNewKeyAndUntagsOldKey(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/UpdateSecretVersionStageRequest::setRemoveFromVersionId → KILLED

152

1.1
Location : putSecretValue
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyPutSecretValueStoresKey(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::putSecretValue → KILLED

170

1.1
Location : putSecretValue
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyPutSecretValueStoresKeys(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/PutSecretValueRequest::setSecretId → KILLED

171

1.1
Location : putSecretValue
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyPutSecretValueStoresKeys(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/PutSecretValueRequest::setClientRequestToken → KILLED

172

1.1
Location : putSecretValue
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyPutSecretValueStoresKeys(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/PutSecretValueRequest::setVersionStages → KILLED

173

1.1
Location : putSecretValue
Killed by : none
Replaced integer multiplication with division → SURVIVED

2.2
Location : putSecretValue
Killed by : none
removed call to java/io/ByteArrayOutputStream::close → NO_COVERAGE

3.3
Location : putSecretValue
Killed by : none
removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE

175

1.1
Location : putSecretValue
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyPutSecretValueStoresKeys(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/macasaet/fernet/Key::writeTo → KILLED

178

1.1
Location : putSecretValue
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyPutSecretValueStoresKeys(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
removed call to com/amazonaws/services/secretsmanager/model/PutSecretValueRequest::setSecretBinary → KILLED

180

1.1
Location : putSecretValue
Killed by : none
removed call to java/io/ByteArrayOutputStream::reset → SURVIVED

181

1.1
Location : putSecretValue
Killed by : none
changed conditional boundary → SURVIVED

2.2
Location : putSecretValue
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyPutSecretValueStoresKeys(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
Changed increment from -1 to 1 → KILLED

3.3
Location : putSecretValue
Killed by : none
negated conditional → SURVIVED

4.4
Location : putSecretValue
Killed by : none
removed call to java/io/ByteArrayOutputStream::write → SURVIVED

182

1.1
Location : putSecretValue
Killed by : none
removed call to java/io/ByteArrayOutputStream::close → SURVIVED

191

1.1
Location : getDelegate
Killed by : com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest.verifyAssertDoesNothing(com.macasaet.fernet.aws.secretsmanager.rotation.SecretsManagerTest)
mutated return of Object value for com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::getDelegate to ( if (x != null) null else throw new RuntimeException ) → KILLED

Active mutators

Tests examined


Report generated by PIT 1.4.10