• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FIWARE / trusted-issuers-list / 79

13 May 2026 10:47AM UTC coverage: 87.146% (+2.6%) from 84.584%
79

Pull #26

github

web-flow
Delete IMPLEMENTATION_PLAN.md
Pull Request #26: enable v5 api

147 of 187 branches covered (78.61%)

Branch coverage included in aggregate %.

497 of 548 new or added lines in 16 files covered. (90.69%)

592 of 661 relevant lines covered (89.56%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.85
/src/main/java/org/fiware/iam/TIRv5Mapper.java
1
/*
2
 * Copyright 2023 FIWARE Foundation e.V. and/or its affiliates
3
 * and other contributors as indicated by the @author tags.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.fiware.iam;
18

19
import com.fasterxml.jackson.core.JsonProcessingException;
20
import com.fasterxml.jackson.databind.ObjectMapper;
21
import com.fasterxml.jackson.databind.ObjectWriter;
22
import java.security.MessageDigest;
23
import java.util.Base64;
24
import java.util.Objects;
25
import lombok.SneakyThrows;
26
import org.fiware.iam.repository.Claim;
27
import org.fiware.iam.repository.Credential;
28
import org.fiware.iam.til.model.ClaimVO;
29
import org.fiware.iam.til.model.CredentialsVO;
30
import org.fiware.iam.tir.v5.model.AttributeDetailsVO;
31
import org.fiware.iam.tir.v5.model.AttributeVO;
32
import org.mapstruct.Mapper;
33
import org.mapstruct.Mapping;
34
import org.slf4j.Logger;
35
import org.slf4j.LoggerFactory;
36

37
/**
38
 * Responsible for mapping entities to the TIR v5 API response models.
39
 *
40
 * <p>Handles Base64 encoding of credential bodies, SHA-256 hex-encoded hashing for attribute IDs,
41
 * and mapping of v5-specific fields ({@code issuerType}, {@code tao}, {@code rootTao}).
42
 *
43
 * @author <a href="https://github.com/wistefan">Stefan Wiedemann</a>
44
 */
45
@Mapper(componentModel = "jsr330")
46
public interface TIRv5Mapper {
47

48
  Logger LOGGER = LoggerFactory.getLogger(TIRv5Mapper.class);
1✔
49
  ObjectWriter OBJECT_WRITER = new ObjectMapper().writer();
1✔
50

51
  /** SHA-256 algorithm name used for attribute ID computation. */
52
  String SHA256_ALGORITHM = "SHA-256";
53

54
  /** Number of hex characters per byte. */
55
  int HEX_CHARS_PER_BYTE = 2;
56

57
  /** Format string for converting a byte to a two-character hex string. */
58
  String HEX_FORMAT = "%02x";
59

60
  /**
61
   * Maps a {@link Credential} entity to a TIL {@link CredentialsVO} for JSON serialization.
62
   *
63
   * <p>This is auto-generated by MapStruct and used internally to produce the JSON payload that is
64
   * then Base64-encoded for the v5 attribute body.
65
   *
66
   * @param credential the credential entity
67
   * @return the TIL credentials value object
68
   */
69
  @Mapping(target = "validFor.from", source = "validFrom")
70
  @Mapping(target = "validFor.to", source = "validTo")
71
  CredentialsVO credentialToCredentialsVO(Credential credential);
72

73
  /**
74
   * Maps a {@link Claim} entity to a {@link ClaimVO}.
75
   *
76
   * <p>Handles the deserialization of stored claim values back to their original object
77
   * representations. Reuses {@link TILMapper#readToObject} for value parsing.
78
   *
79
   * @param claim the claim entity
80
   * @return the claim value object
81
   */
82
  default ClaimVO claimToClaimVO(Claim claim) {
83
    return new ClaimVO()
1✔
84
        .name(claim.getName())
1✔
85
        .path(claim.getPath())
1✔
86
        .allowedValues(
1✔
87
            claim.getClaimValues().stream()
1✔
88
                .map(TILMapper::readToObject)
1✔
89
                .filter(Objects::nonNull)
1✔
90
                .toList());
1✔
91
  }
92

93
  /**
94
   * Maps a {@link Credential} entity to a v5 {@link AttributeVO}.
95
   *
96
   * <p>Serializes the credential to JSON, Base64-encodes the body, computes a SHA-256 hex-encoded
97
   * hash, and maps the v5-specific fields ({@code issuerType}, {@code tao}, {@code rootTao}).
98
   *
99
   * @param credential the credential entity
100
   * @return the v5 attribute value object
101
   */
102
  default AttributeVO credentialToAttributeVO(Credential credential) {
103
    CredentialsVO credentialsVO = credentialToCredentialsVO(credential);
1✔
104
    AttributeVO attributeVO = new AttributeVO();
1✔
105
    try {
106
      byte[] body = OBJECT_WRITER.writeValueAsBytes(credentialsVO);
1✔
107
      attributeVO.setBody(Base64.getEncoder().encodeToString(body));
1✔
108
      attributeVO.setHash(bytesToHex(getSHA256(body)));
1✔
NEW
109
    } catch (JsonProcessingException e) {
×
NEW
110
      LOGGER.warn(
×
111
          "Was not able to process credential {}. Will not include full data.",
NEW
112
          credential.getId(),
×
113
          e);
114
    }
1✔
115
    attributeVO.setIssuerType(mapIssuerType(credential.getIssuerType()));
1✔
116
    attributeVO.setTao(credential.getTao());
1✔
117
    attributeVO.setRootTao(credential.getRootTao());
1✔
118
    return attributeVO;
1✔
119
  }
120

121
  /**
122
   * Computes the v5 attribute ID for a credential as a SHA-256 hex-encoded hash of the
123
   * Base64-encoded credential body.
124
   *
125
   * @param credential the credential entity
126
   * @return the hex-encoded SHA-256 hash, or an empty string if serialization fails
127
   */
128
  default String computeAttributeId(Credential credential) {
129
    CredentialsVO credentialsVO = credentialToCredentialsVO(credential);
1✔
130
    try {
131
      byte[] body = OBJECT_WRITER.writeValueAsBytes(credentialsVO);
1✔
132
      return bytesToHex(getSHA256(body));
1✔
NEW
133
    } catch (JsonProcessingException e) {
×
NEW
134
      LOGGER.warn("Was not able to compute attribute ID for credential {}.", credential.getId(), e);
×
NEW
135
      return "";
×
136
    }
137
  }
138

139
  /**
140
   * Maps a {@link Credential} entity to a v5 {@link AttributeDetailsVO}, wrapping the attribute
141
   * with the issuer's DID.
142
   *
143
   * @param did the issuer's DID
144
   * @param credential the credential entity
145
   * @return the attribute details value object
146
   */
147
  default AttributeDetailsVO credentialToAttributeDetailsVO(String did, Credential credential) {
148
    AttributeDetailsVO details = new AttributeDetailsVO();
1✔
149
    details.setDid(did);
1✔
150
    details.setAttribute(credentialToAttributeVO(credential));
1✔
151
    return details;
1✔
152
  }
153

154
  /**
155
   * Maps an issuer type string from the database to the v5 {@link AttributeVO.IssuerType} enum.
156
   *
157
   * <p>Returns {@link AttributeVO.IssuerType#UNDEFINED} for null or unrecognized values.
158
   *
159
   * @param issuerType the issuer type string, may be null
160
   * @return the corresponding enum value
161
   */
162
  default AttributeVO.IssuerType mapIssuerType(String issuerType) {
163
    if (issuerType == null) {
1!
164
      return AttributeVO.IssuerType.UNDEFINED;
1✔
165
    }
NEW
166
    return AttributeVO.IssuerType.toOptional(issuerType).orElse(AttributeVO.IssuerType.UNDEFINED);
×
167
  }
168

169
  /**
170
   * Computes the SHA-256 hash of the given byte array.
171
   *
172
   * @param toHash the data to hash
173
   * @return the SHA-256 hash bytes
174
   */
NEW
175
  @SneakyThrows
×
176
  default byte[] getSHA256(byte[] toHash) {
177
    MessageDigest digest = MessageDigest.getInstance(SHA256_ALGORITHM);
1✔
178
    return digest.digest(toHash);
1✔
179
  }
180

181
  /**
182
   * Converts a byte array to a lowercase hexadecimal string.
183
   *
184
   * @param bytes the byte array to convert
185
   * @return the hex-encoded string
186
   */
187
  default String bytesToHex(byte[] bytes) {
188
    StringBuilder sb = new StringBuilder(bytes.length * HEX_CHARS_PER_BYTE);
1✔
189
    for (byte b : bytes) {
1✔
190
      sb.append(String.format(HEX_FORMAT, b));
1✔
191
    }
192
    return sb.toString();
1✔
193
  }
194
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc