Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 56cd8b1

Browse files
committedJan 4, 2025·
Add validation to Attribute DTO and fix Sonar issues
1 parent 27a2cc9 commit 56cd8b1

File tree

4 files changed

+83
-12
lines changed

4 files changed

+83
-12
lines changed
 

‎iam-login-service/src/main/java/it/infn/mw/iam/api/account/labels/AccountLabelsController.java

+6-11
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,21 @@
1818
import static it.infn.mw.iam.api.utils.ValidationErrorUtils.stringifyValidationError;
1919
import static java.lang.String.format;
2020
import static org.springframework.http.HttpStatus.NO_CONTENT;
21-
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
22-
import static org.springframework.web.bind.annotation.RequestMethod.GET;
23-
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
2421

2522
import java.util.List;
2623
import java.util.function.Supplier;
2724

28-
import org.springframework.beans.factory.annotation.Autowired;
2925
import org.springframework.http.HttpStatus;
3026
import org.springframework.security.access.prepost.PreAuthorize;
3127
import org.springframework.validation.BindingResult;
3228
import org.springframework.validation.annotation.Validated;
29+
import org.springframework.web.bind.annotation.DeleteMapping;
3330
import org.springframework.web.bind.annotation.ExceptionHandler;
31+
import org.springframework.web.bind.annotation.GetMapping;
3432
import org.springframework.web.bind.annotation.PathVariable;
33+
import org.springframework.web.bind.annotation.PutMapping;
3534
import org.springframework.web.bind.annotation.RequestBody;
3635
import org.springframework.web.bind.annotation.RequestMapping;
37-
import org.springframework.web.bind.annotation.ResponseBody;
3836
import org.springframework.web.bind.annotation.ResponseStatus;
3937
import org.springframework.web.bind.annotation.RestController;
4038

@@ -58,7 +56,6 @@ public class AccountLabelsController {
5856
final IamAccountService service;
5957
final LabelDTOConverter converter;
6058

61-
@Autowired
6259
public AccountLabelsController(IamAccountService service, LabelDTOConverter converter) {
6360
this.service = service;
6461
this.converter = converter;
@@ -74,7 +71,7 @@ private void handleValidationError(BindingResult result) {
7471
}
7572
}
7673

77-
@RequestMapping(method = GET)
74+
@GetMapping
7875
@PreAuthorize("#iam.hasScope('iam:admin.read') or #iam.hasAnyDashboardRole('ROLE_ADMIN', 'ROLE_GM') or #iam.isUser(#id)")
7976
public List<LabelDTO> getLabels(@PathVariable String id) {
8077

@@ -87,7 +84,7 @@ public List<LabelDTO> getLabels(@PathVariable String id) {
8784
return results;
8885
}
8986

90-
@RequestMapping(method = PUT)
87+
@PutMapping
9188
@PreAuthorize("#iam.hasScope('iam:admin.write') or #iam.hasDashboardRole('ROLE_ADMIN')")
9289
public void setLabel(@PathVariable String id, @RequestBody @Validated LabelDTO label,
9390
BindingResult validationResult) {
@@ -97,7 +94,7 @@ public void setLabel(@PathVariable String id, @RequestBody @Validated LabelDTO l
9794
service.addLabel(account, converter.entityFromDto(label));
9895
}
9996

100-
@RequestMapping(method = DELETE)
97+
@DeleteMapping
10198
@PreAuthorize("#iam.hasScope('iam:admin.write') or #iam.hasDashboardRole('ROLE_ADMIN')")
10299
@ResponseStatus(NO_CONTENT)
103100
public void deleteLabel(@PathVariable String id, @Validated LabelDTO label,
@@ -109,14 +106,12 @@ public void deleteLabel(@PathVariable String id, @Validated LabelDTO label,
109106

110107
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
111108
@ExceptionHandler(InvalidLabelError.class)
112-
@ResponseBody
113109
public ErrorDTO handleValidationError(InvalidLabelError e) {
114110
return ErrorDTO.fromString(e.getMessage());
115111
}
116112

117113
@ResponseStatus(code = HttpStatus.NOT_FOUND)
118114
@ExceptionHandler(NoSuchAccountError.class)
119-
@ResponseBody
120115
public ErrorDTO handleNotFoundError(NoSuchAccountError e) {
121116
return ErrorDTO.fromString(e.getMessage());
122117
}

‎iam-login-service/src/main/java/it/infn/mw/iam/api/common/AttributeDTO.java

+5
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
package it.infn.mw.iam.api.common;
1717

1818
import javax.annotation.Generated;
19+
import javax.validation.constraints.NotBlank;
1920
import javax.validation.constraints.Pattern;
2021
import javax.validation.constraints.Size;
2122

23+
import it.infn.mw.iam.api.common.validator.NoNewLineOrCarriageReturn;
24+
2225

2326

2427
public class AttributeDTO {
@@ -28,9 +31,11 @@ public class AttributeDTO {
2831
@Size(max = 64, message = "name cannot be longer than 64 chars")
2932
@Pattern(regexp = NAME_REGEXP,
3033
message = "invalid name (does not match with regexp: '" + NAME_REGEXP + "')")
34+
@NotBlank
3135
private String name;
3236

3337
@Size(max = 256, message = "value cannot be longer than 256 chars")
38+
@NoNewLineOrCarriageReturn
3439
private String value;
3540

3641
public AttributeDTO() {

‎iam-login-service/src/main/java/it/infn/mw/iam/api/common/validator/NoNewLineOrCarriageReturnValidator.java

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
/**
2+
* Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2016-2021
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+
* http://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+
*/
116
package it.infn.mw.iam.api.common.validator;
217

318
import javax.validation.ConstraintValidator;

‎iam-login-service/src/test/java/it/infn/mw/iam/test/api/account/attributes/AccountAttributesTests.java

+57-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static java.lang.String.format;
1919
import static java.util.Arrays.asList;
20+
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
2021
import static org.hamcrest.CoreMatchers.containsString;
2122
import static org.hamcrest.CoreMatchers.equalTo;
2223
import static org.hamcrest.CoreMatchers.hasItem;
@@ -67,6 +68,7 @@ public class AccountAttributesTests {
6768
public static final ResultMatcher UNAUTHORIZED = status().isUnauthorized();
6869
public static final ResultMatcher FORBIDDEN = status().isForbidden();
6970
public static final ResultMatcher NOT_FOUND = status().isNotFound();
71+
public static final ResultMatcher BAD_REQUEST = status().isBadRequest();
7072

7173
public static final String TEST_USER = "test";
7274
public static final String TEST_100_USER = "test_100";
@@ -145,7 +147,7 @@ public void aUserCanListHisAttributes() throws Exception {
145147

146148
mvc.perform(get(ACCOUNT_ATTR_URL_TEMPLATE, testAccount.getUuid())).andExpect(OK);
147149
}
148-
150+
149151
@Test
150152
@WithMockUser(username = "test", roles = "USER")
151153
public void managingAttributesRequiresPrivilegedUser() throws Exception {
@@ -390,4 +392,58 @@ public void multiAttributeSetTest() throws Exception {
390392
attrs.forEach(a -> assertThat(results, hasItem(a)));
391393
}
392394
}
395+
396+
@Test
397+
@WithMockUser(username = "admin", roles = "ADMIN")
398+
public void attributeValidationTests() throws Exception {
399+
400+
AttributeDTO noNameAttribute = AttributeDTO.newInstance(null, ATTR_VALUE);
401+
402+
mvc
403+
.perform(put(ACCOUNT_ATTR_URL_TEMPLATE, noNameAttribute).contentType(APPLICATION_JSON)
404+
.content(mapper.writeValueAsString(noNameAttribute)))
405+
.andExpect(BAD_REQUEST)
406+
.andExpect(jsonPath("$.error", containsString("must not be blank")));
407+
408+
final String SOME_INVALID_NAMES[] =
409+
{"-pippo", "/ciccio/paglia", ".starts-with-dot", "carriage\nreturn", "another\rreturn"};
410+
411+
for (String name : SOME_INVALID_NAMES) {
412+
AttributeDTO invalidAttribute = AttributeDTO.newInstance(name, ATTR_VALUE);
413+
mvc
414+
.perform(put(ACCOUNT_ATTR_URL_TEMPLATE, invalidAttribute).contentType(APPLICATION_JSON)
415+
.content(mapper.writeValueAsString(invalidAttribute)))
416+
.andExpect(BAD_REQUEST)
417+
.andExpect(jsonPath("$.error", containsString("invalid name (does not match with regexp")));
418+
}
419+
420+
final String SOME_INVALID_VALES[] = {"carriage\nreturn", "another\rreturn"};
421+
422+
for (String value : SOME_INVALID_VALES) {
423+
AttributeDTO invalidAttribute = AttributeDTO.newInstance(ATTR_NAME, value);
424+
mvc
425+
.perform(put(ACCOUNT_ATTR_URL_TEMPLATE, invalidAttribute).contentType(APPLICATION_JSON)
426+
.content(mapper.writeValueAsString(invalidAttribute)))
427+
.andExpect(BAD_REQUEST)
428+
.andExpect(jsonPath("$.error",
429+
containsString("The string must not contain any new line or carriage return")));
430+
}
431+
432+
AttributeDTO longNameAttribute = AttributeDTO.newInstance(randomAlphabetic(65), ATTR_VALUE);
433+
434+
mvc
435+
.perform(put(ACCOUNT_ATTR_URL_TEMPLATE, longNameAttribute).contentType(APPLICATION_JSON)
436+
.content(mapper.writeValueAsString(longNameAttribute)))
437+
.andExpect(BAD_REQUEST)
438+
.andExpect(jsonPath("$.error", containsString("name cannot be longer than 64 chars")));
439+
440+
441+
AttributeDTO longValueAttribute = AttributeDTO.newInstance(ATTR_NAME, randomAlphabetic(257));
442+
443+
mvc
444+
.perform(put(ACCOUNT_ATTR_URL_TEMPLATE, longValueAttribute).contentType(APPLICATION_JSON)
445+
.content(mapper.writeValueAsString(longValueAttribute)))
446+
.andExpect(BAD_REQUEST)
447+
.andExpect(jsonPath("$.error", containsString("value cannot be longer than 256 chars")));
448+
}
393449
}

0 commit comments

Comments
 (0)
Please sign in to comment.