Skip to content

Package: MfaOptionServiceImpl

MfaOptionServiceImpl

nameinstructionbranchcomplexitylinemethod
MfaOptionServiceImpl()
M: 35 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
buildImage(BitMatrix)
M: 29 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
count(KapuaQuery)
M: 31 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
create(MfaOptionCreator)
M: 156 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 36 C: 0
0%
M: 1 C: 0
0%
delete(KapuaId, KapuaId)
M: 33 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
disableTrust(KapuaId, KapuaId)
M: 22 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
enableTrust(KapuaId, KapuaId)
M: 45 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 12 C: 0
0%
M: 1 C: 0
0%
enableTrust(MfaOption)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
find(KapuaId, KapuaId)
M: 33 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
findByUserId(KapuaId, KapuaId)
M: 46 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
generateQRCode(String, String, String, String)
M: 46 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%
generateTrustKey()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
imgToBase64(BufferedImage)
M: 14 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
lambda$count$5(KapuaQuery, EntityManager)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$create$0(MfaOptionCreator)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$create$1(MfaOptionCreator)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$delete$6(KapuaId, KapuaId, EntityManager)
M: 16 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
lambda$find$3(KapuaId, KapuaId, EntityManager)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$query$4(KapuaQuery, EntityManager)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$update$2(MfaOption, EntityManager)
M: 20 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
query(KapuaQuery)
M: 30 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 15 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
update(MfaOption)
M: 46 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2020, 2022 Eurotech and/or its affiliates and others
3: *
4: * This program and the accompanying materials are made
5: * available under the terms of the Eclipse Public License 2.0
6: * which is available at https://www.eclipse.org/legal/epl-2.0/
7: *
8: * SPDX-License-Identifier: EPL-2.0
9: *
10: * Contributors:
11: * Eurotech - initial API and implementation
12: *******************************************************************************/
13: package org.eclipse.kapua.service.authentication.credential.mfa.shiro;
14:
15: import com.google.zxing.BarcodeFormat;
16: import com.google.zxing.WriterException;
17: import com.google.zxing.client.j2se.MatrixToImageWriter;
18: import com.google.zxing.common.BitMatrix;
19: import com.google.zxing.qrcode.QRCodeWriter;
20: import org.apache.commons.lang.time.DateUtils;
21: import org.apache.http.client.utils.URIBuilder;
22: import org.eclipse.kapua.KapuaEntityNotFoundException;
23: import org.eclipse.kapua.KapuaException;
24: import org.eclipse.kapua.commons.jpa.EntityManager;
25: import org.eclipse.kapua.commons.security.KapuaSecurityUtils;
26: import org.eclipse.kapua.commons.security.KapuaSession;
27: import org.eclipse.kapua.commons.service.internal.AbstractKapuaService;
28: import org.eclipse.kapua.commons.util.ArgumentValidator;
29: import org.eclipse.kapua.commons.util.KapuaExceptionUtils;
30: import org.eclipse.kapua.locator.KapuaLocator;
31: import org.eclipse.kapua.locator.KapuaProvider;
32: import org.eclipse.kapua.model.KapuaEntityAttributes;
33: import org.eclipse.kapua.model.domain.Actions;
34: import org.eclipse.kapua.model.id.KapuaId;
35: import org.eclipse.kapua.model.query.KapuaQuery;
36: import org.eclipse.kapua.model.query.predicate.QueryPredicate;
37: import org.eclipse.kapua.service.account.Account;
38: import org.eclipse.kapua.service.account.AccountService;
39: import org.eclipse.kapua.service.authentication.AuthenticationDomains;
40: import org.eclipse.kapua.service.authentication.credential.mfa.KapuaExistingMfaOptionException;
41: import org.eclipse.kapua.service.authentication.credential.mfa.MfaOption;
42: import org.eclipse.kapua.service.authentication.credential.mfa.MfaOptionAttributes;
43: import org.eclipse.kapua.service.authentication.credential.mfa.MfaOptionCreator;
44: import org.eclipse.kapua.service.authentication.credential.mfa.MfaOptionListResult;
45: import org.eclipse.kapua.service.authentication.credential.mfa.MfaOptionQuery;
46: import org.eclipse.kapua.service.authentication.credential.mfa.MfaOptionService;
47: import org.eclipse.kapua.service.authentication.credential.mfa.ScratchCodeCreator;
48: import org.eclipse.kapua.service.authentication.credential.mfa.ScratchCodeFactory;
49: import org.eclipse.kapua.service.authentication.credential.mfa.ScratchCodeListResult;
50: import org.eclipse.kapua.service.authentication.credential.mfa.ScratchCodeService;
51: import org.eclipse.kapua.service.authentication.mfa.MfaAuthenticator;
52: import org.eclipse.kapua.service.authentication.shiro.AuthenticationEntityManagerFactory;
53: import org.eclipse.kapua.service.authentication.shiro.mfa.MfaAuthenticatorServiceLocator;
54: import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSetting;
55: import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSettingKeys;
56: import org.eclipse.kapua.service.authentication.shiro.utils.AuthenticationUtils;
57: import org.eclipse.kapua.service.authentication.shiro.utils.CryptAlgorithm;
58: import org.eclipse.kapua.service.authorization.AuthorizationService;
59: import org.eclipse.kapua.service.authorization.permission.PermissionFactory;
60: import org.eclipse.kapua.service.authorization.shiro.exception.InternalUserOnlyException;
61: import org.eclipse.kapua.service.authorization.shiro.exception.SelfManagedOnlyException;
62: import org.eclipse.kapua.service.user.User;
63: import org.eclipse.kapua.service.user.UserService;
64: import org.eclipse.kapua.service.user.UserType;
65: import org.slf4j.Logger;
66: import org.slf4j.LoggerFactory;
67:
68: import javax.imageio.ImageIO;
69: import java.awt.Color;
70: import java.awt.Graphics;
71: import java.awt.image.BufferedImage;
72: import java.io.ByteArrayOutputStream;
73: import java.io.IOException;
74: import java.net.URI;
75: import java.net.URISyntaxException;
76: import java.util.Base64;
77: import java.util.Date;
78: import java.util.UUID;
79:
80: /**
81: * {@link MfaOptionService} implementation.
82: *
83: * @since 1.3.0
84: */
85: @KapuaProvider
86: public class MfaOptionServiceImpl extends AbstractKapuaService implements MfaOptionService {
87:
88: private static final Logger LOGGER = LoggerFactory.getLogger(MfaOptionServiceImpl.class);
89:
90: private static final MfaAuthenticatorServiceLocator MFA_AUTH_SERVICE_LOCATOR = MfaAuthenticatorServiceLocator.getInstance();
91: private static final MfaAuthenticator MFA_AUTHENTICATOR = MFA_AUTH_SERVICE_LOCATOR.getMfaAuthenticator();
92:
93: private static final KapuaAuthenticationSetting AUTHENTICATION_SETTING = KapuaAuthenticationSetting.getInstance();
94: private static final int TRUST_KEY_DURATION = AUTHENTICATION_SETTING.getInt(KapuaAuthenticationSettingKeys.AUTHENTICATION_MFA_TRUST_KEY_DURATION);
95: private static final int QR_CODE_SIZE = 134; // TODO: make this configurable?
96: private static final String IMAGE_FORMAT = "png";
97:
98: private final KapuaLocator locator = KapuaLocator.getInstance();
99:
100: private final AccountService accountService = locator.getService(AccountService.class);
101: private final ScratchCodeService scratchCodeService = locator.getService(ScratchCodeService.class);
102: private final ScratchCodeFactory scratchCodeFactory = locator.getFactory(ScratchCodeFactory.class);
103:
104: private final UserService userService = locator.getService(UserService.class);
105:
106: /**
107: * Constructor.
108: *
109: * @since 1.3.0
110: */
111: public MfaOptionServiceImpl() {
112: super(MfaOptionEntityManagerFactory.getInstance());
113: }
114:
115: @Override
116: public MfaOption create(MfaOptionCreator mfaOptionCreator) throws KapuaException {
117: //
118: // Argument Validation
119: ArgumentValidator.notNull(mfaOptionCreator, "mfaOptionCreator");
120: ArgumentValidator.notNull(mfaOptionCreator.getScopeId(), "mfaOptionCreator.scopeId");
121: ArgumentValidator.notNull(mfaOptionCreator.getUserId(), "mfaOptionCreator.userId");
122:
123: //
124: // Check access
125: KapuaLocator locator = KapuaLocator.getInstance();
126: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
127: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
128: authorizationService.checkPermission(permissionFactory.newPermission(AuthenticationDomains.CREDENTIAL_DOMAIN, Actions.write, mfaOptionCreator.getScopeId()));
129:
130: //
131: // Check that the operation is carried by the user itself
132: KapuaSession session = KapuaSecurityUtils.getSession();
133: KapuaId expectedUser = session.getUserId();
134:• if (!expectedUser.equals(mfaOptionCreator.getUserId())) {
135: throw new SelfManagedOnlyException();
136: }
137:
138: //
139: // Check that the user is an internal user (external users cannot have the MFA enabled)
140: final MfaOptionCreator finalMfaOptionCreator = mfaOptionCreator;
141: User user = KapuaSecurityUtils.doPrivileged(() -> userService.find(finalMfaOptionCreator.getScopeId(), finalMfaOptionCreator.getUserId()));
142:• if (!user.getUserType().equals(UserType.INTERNAL) || user.getExternalId() != null) {
143: throw new InternalUserOnlyException();
144: }
145:
146: //
147: // Check existing MfaOption
148: MfaOption existingMfaOption = findByUserId(mfaOptionCreator.getScopeId(), mfaOptionCreator.getUserId());
149:• if (existingMfaOption != null) {
150: throw new KapuaExistingMfaOptionException();
151: }
152:
153: //
154: // Do create
155: MfaOption mfaOption;
156: EntityManager em = AuthenticationEntityManagerFactory.getEntityManager();
157: try {
158: em.beginTransaction();
159:
160: String fullKey = MFA_AUTHENTICATOR.generateKey();
161: mfaOptionCreator = new MfaOptionCreatorImpl(mfaOptionCreator.getScopeId(), mfaOptionCreator.getUserId(), fullKey);
162: mfaOption = MfaOptionDAO.create(em, mfaOptionCreator);
163: mfaOption = MfaOptionDAO.find(em, mfaOption.getScopeId(), mfaOption.getId());
164:
165: // generating base64 QR code image
166: Account account = KapuaSecurityUtils.doPrivileged(() -> accountService.find(finalMfaOptionCreator.getScopeId()));
167: mfaOption.setQRCodeImage(generateQRCode(account.getOrganization().getName(), account.getName(), user.getName(), fullKey));
168:
169: em.commit();
170:
171: // generating scratch codes
172: final ScratchCodeCreator scratchCodeCreator = scratchCodeFactory.newCreator(mfaOptionCreator.getScopeId(), mfaOption.getId(), null);
173: final ScratchCodeListResult scratchCodeListResult = scratchCodeService.createAllScratchCodes(scratchCodeCreator);
174: mfaOption.setScratchCodes(scratchCodeListResult.getItems());
175:
176: // Do post persist magic on key value (note that this is the only place in which the key is returned in plain-text)
177: mfaOption.setMfaSecretKey(fullKey);
178: } catch (Exception pe) {
179: em.rollback();
180: throw KapuaExceptionUtils.convertPersistenceException(pe);
181: } finally {
182: em.close();
183: }
184:
185: return mfaOption;
186: }
187:
188: @Override
189: public MfaOption update(MfaOption mfaOption) throws KapuaException {
190: //
191: // Argument Validation
192: ArgumentValidator.notNull(mfaOption, "mfaOption");
193: ArgumentValidator.notNull(mfaOption.getId(), "mfaOption.id");
194: ArgumentValidator.notNull(mfaOption.getScopeId(), "mfaOption.scopeId");
195: ArgumentValidator.notNull(mfaOption.getUserId(), "mfaOption.userId");
196: ArgumentValidator.notEmptyOrNull(mfaOption.getMfaSecretKey(), "mfaOption.mfaSecretKey");
197:
198: //
199: // Check access
200: KapuaLocator locator = KapuaLocator.getInstance();
201: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
202: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
203: authorizationService.checkPermission(permissionFactory.newPermission(AuthenticationDomains.CREDENTIAL_DOMAIN, Actions.write, mfaOption.getScopeId()));
204:
205: return entityManagerSession.doTransactedAction(em -> {
206: MfaOption currentMfaOption = MfaOptionDAO.find(em, mfaOption.getScopeId(), mfaOption.getId());
207:
208:• if (currentMfaOption == null) {
209: throw new KapuaEntityNotFoundException(MfaOption.TYPE, mfaOption.getId());
210: }
211:
212: // Passing attributes??
213: return MfaOptionDAO.update(em, mfaOption);
214: });
215: }
216:
217: @Override
218: public MfaOption find(KapuaId scopeId, KapuaId mfaOptionId) throws KapuaException {
219: // Validation of the fields
220: ArgumentValidator.notNull(scopeId, KapuaEntityAttributes.SCOPE_ID);
221: ArgumentValidator.notNull(mfaOptionId, "mfaOptionId");
222:
223: //
224: // Check Access
225: KapuaLocator locator = KapuaLocator.getInstance();
226: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
227: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
228: authorizationService.checkPermission(permissionFactory.newPermission(AuthenticationDomains.CREDENTIAL_DOMAIN, Actions.read, scopeId));
229:
230: return entityManagerSession.doAction(em -> MfaOptionDAO.find(em, scopeId, mfaOptionId));
231: }
232:
233: @Override
234: public MfaOptionListResult query(KapuaQuery query) throws KapuaException {
235: //
236: // Argument Validation
237: ArgumentValidator.notNull(query, "query");
238:
239: //
240: // Check Access
241: KapuaLocator locator = KapuaLocator.getInstance();
242: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
243: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
244: authorizationService.checkPermission(permissionFactory.newPermission(AuthenticationDomains.CREDENTIAL_DOMAIN, Actions.read, query.getScopeId()));
245:
246: return entityManagerSession.doAction(em -> MfaOptionDAO.query(em, query));
247: }
248:
249: @Override
250: public long count(KapuaQuery query) throws KapuaException {
251: //
252: // Argument Validation
253: ArgumentValidator.notNull(query, "query");
254:
255: //
256: // Check Access
257: KapuaLocator locator = KapuaLocator.getInstance();
258: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
259: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
260: authorizationService.checkPermission(permissionFactory.newPermission(AuthenticationDomains.CREDENTIAL_DOMAIN, Actions.read, query.getScopeId()));
261:
262: return entityManagerSession.doAction(em -> MfaOptionDAO.count(em, query));
263: }
264:
265: @Override
266: public void delete(KapuaId scopeId, KapuaId mfaOptionId) throws KapuaException {
267: //
268: // Argument Validation
269: ArgumentValidator.notNull(mfaOptionId, "mfaOptionId");
270: ArgumentValidator.notNull(scopeId, "scopeId");
271:
272: //
273: // Check Access
274: KapuaLocator locator = KapuaLocator.getInstance();
275: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
276: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
277: authorizationService.checkPermission(permissionFactory.newPermission(AuthenticationDomains.CREDENTIAL_DOMAIN, Actions.delete, scopeId));
278:
279: entityManagerSession.doTransactedAction(em -> {
280:• if (MfaOptionDAO.find(em, scopeId, mfaOptionId) == null) {
281: throw new KapuaEntityNotFoundException(MfaOption.TYPE, mfaOptionId);
282: }
283: return MfaOptionDAO.delete(em, scopeId, mfaOptionId);
284: });
285: }
286:
287: @Override
288: public MfaOption findByUserId(KapuaId scopeId, KapuaId userId) throws KapuaException {
289: //
290: // Argument Validation
291: ArgumentValidator.notNull(scopeId, KapuaEntityAttributes.SCOPE_ID);
292: ArgumentValidator.notNull(userId, MfaOptionAttributes.USER_ID);
293:
294: //
295: // Check Access
296: KapuaLocator locator = KapuaLocator.getInstance();
297: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
298: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
299: authorizationService.checkPermission(permissionFactory.newPermission(AuthenticationDomains.CREDENTIAL_DOMAIN, Actions.read, scopeId));
300:
301: //
302: // Build query
303: MfaOptionQuery query = new MfaOptionQueryImpl(scopeId);
304: QueryPredicate predicate = query.attributePredicate(MfaOptionAttributes.USER_ID, userId);
305: query.setPredicate(predicate);
306:
307: //
308: // Query and return result
309: MfaOptionListResult result = query(query);
310:
311: return result.getFirstItem();
312: }
313:
314: @Override
315: public String enableTrust(MfaOption mfaOption) throws KapuaException {
316:
317: // Argument Validation (fields validation is performed inside the 'update' method)
318: ArgumentValidator.notNull(mfaOption, "mfaOption");
319:
320: return enableTrust(mfaOption.getScopeId(), mfaOption.getId());
321: }
322:
323: @Override
324: public String enableTrust(KapuaId scopeId, KapuaId mfaOptionId) throws KapuaException {
325: //
326: // Argument Validation
327: ArgumentValidator.notNull(scopeId, "scopeId");
328: ArgumentValidator.notNull(mfaOptionId, "mfaOptionId");
329:
330: //
331: // Checking existence
332: MfaOption mfaOption = find(scopeId, mfaOptionId);
333:
334:• if (mfaOption == null) {
335: throw new KapuaEntityNotFoundException(MfaOption.TYPE, mfaOptionId);
336: }
337:
338: // Trust key generation always performed
339: // This allows the use only of a single trusted machine,
340: // until a solution with different trust keys is implemented!
341: String trustKey = generateTrustKey();
342: mfaOption.setTrustKey(AuthenticationUtils.cryptCredential(CryptAlgorithm.BCRYPT, trustKey));
343:
344: Date expirationDate = new Date(System.currentTimeMillis());
345: expirationDate = DateUtils.addDays(expirationDate, TRUST_KEY_DURATION);
346: mfaOption.setTrustExpirationDate(expirationDate);
347:
348: // Update
349: update(mfaOption);
350:
351: return trustKey;
352: }
353:
354: @Override
355: public void disableTrust(KapuaId scopeId, KapuaId mfaOptionId) throws KapuaException {
356:
357: // Argument Validation
358: ArgumentValidator.notNull(mfaOptionId, "mfaOptionId");
359: ArgumentValidator.notNull(scopeId, "scopeId");
360:
361: // extracting the MfaOption
362: MfaOption mfaOption = find(scopeId, mfaOptionId);
363:
364: // Reset the trust machine fields
365: mfaOption.setTrustKey(null);
366: mfaOption.setTrustExpirationDate(null);
367:
368: update(mfaOption);
369: }
370:
371: /**
372: * Generate the trust key string.
373: *
374: * @return String
375: * @since 1.3.0
376: */
377: private String generateTrustKey() {
378: return UUID.randomUUID().toString();
379: }
380:
381: /**
382: * Produce a QR code in base64 format for the authenticator app.
383: * This QR code generator follows the spec detailed here for the URI format: https://github.com/google/google-authenticator/wiki/Key-Uri-Format
384: *
385: * @param organizationName the organization name to be used as issuer in the QR code
386: * @param accountName the account name of the account to which the user belongs
387: * @param username the username
388: * @param key the Mfa secret key in plain text
389: * @return the QR code image in base64 format
390: * @since 1.3.0
391: */
392: private String generateQRCode(String organizationName, String accountName, String username, String key)
393: throws IOException, WriterException, URISyntaxException {
394: // url to qr_barcode encoding
395: URI uri = new URIBuilder()
396: .setScheme("otpauth")
397: .setHost("totp")
398: .setPath(organizationName + ":" + username + "@" + accountName)
399: .setParameter("secret", key)
400: .setParameter("issuer", organizationName)
401: .build();
402:
403: BitMatrix bitMatrix = new QRCodeWriter().encode(uri.toString(), BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE);
404: BufferedImage image = buildImage(bitMatrix);
405: return imgToBase64(image);
406: }
407:
408: /**
409: * Converts a {@link BufferedImage} to base64 string format
410: *
411: * @param img the {@link BufferedImage} to convert
412: * @return the base64 string representation of the input image
413: * @since 1.3.0
414: */
415: private static String imgToBase64(BufferedImage img) throws IOException {
416: final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
417: ImageIO.write(img, IMAGE_FORMAT, outputStream);
418: return Base64.getEncoder().encodeToString(outputStream.toByteArray());
419: }
420:
421: /**
422: * Converts a {@link BitMatrix} to a {@link BufferedImage}
423: *
424: * @param bitMatrix the {@link BitMatrix} to be converted into ad image
425: * @return the {@link BufferedImage} obtained from the conversion
426: * @since 1.3.0
427: */
428: private static BufferedImage buildImage(BitMatrix bitMatrix) {
429: BufferedImage qrCodeImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
430: BufferedImage resultImage = new BufferedImage(QR_CODE_SIZE, QR_CODE_SIZE, BufferedImage.TYPE_INT_RGB);
431:
432: Graphics g = resultImage.getGraphics();
433: g.drawImage(qrCodeImage, 0, 0, new Color(232, 232, 232, 255), null);
434:
435: return resultImage;
436: }
437: }