54 | 159 | 160 |
12 | *
13 | * public SmsDto save(
14 | * @RequestBody SmsDto dto ,
15 | * @Credentials AuditingCredentials auditingCredentials)
16 | *
17 | *
18 | */
19 | @Target(ElementType.PARAMETER)
20 | @Retention(RetentionPolicy.RUNTIME)
21 | @Documented
22 | public @interface Credentials {
23 |
24 | boolean required() default true;
25 | }
--------------------------------------------------------------------------------
/src/main/java/com/murray/communications/security/jwtaudit/JwtClaimsToAuditingCredientalsResolver.java:
--------------------------------------------------------------------------------
1 | package com.murray.communications.security.jwtaudit;
2 |
3 | import com.murray.communications.security.jwt.JwtTokenProviderService;
4 | import io.jsonwebtoken.Claims;
5 | import org.springframework.core.MethodParameter;
6 | import org.springframework.http.HttpStatus;
7 | import org.springframework.security.authentication.AuthenticationServiceException;
8 | import org.springframework.web.bind.support.WebDataBinderFactory;
9 | import org.springframework.web.client.HttpClientErrorException;
10 | import org.springframework.web.context.request.NativeWebRequest;
11 | import org.springframework.web.method.support.HandlerMethodArgumentResolver;
12 | import org.springframework.web.method.support.ModelAndViewContainer;
13 |
14 | import javax.servlet.http.HttpServletRequest;
15 | import java.util.Objects;
16 |
17 | public class JwtClaimsToAuditingCredientalsResolver implements HandlerMethodArgumentResolver {
18 |
19 | private final JwtTokenProviderService jwtTokenProviderService;
20 |
21 | public JwtClaimsToAuditingCredientalsResolver(JwtTokenProviderService jwtTokenProviderService) {
22 | this.jwtTokenProviderService = jwtTokenProviderService;
23 | }
24 |
25 | @Override
26 | public boolean supportsParameter(MethodParameter parameter) {
27 | return parameter.hasParameterAnnotation(Credentials.class)
28 | && parameter.getParameterType().equals(AuditingCredentials.class);
29 | }
30 |
31 | @Override
32 | public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest request, WebDataBinderFactory webDataBinderFactory) throws Exception {
33 |
34 |
35 | AuditingCredentials credentials = toUserCredentials(request);
36 |
37 | if (Objects.isNull(credentials)) {
38 | throw new AuthenticationServiceException("Auditing credentials are invalid");
39 | }
40 |
41 | return credentials;
42 | }
43 |
44 | /**
45 | * Convert the Claims Token values into {@link AuditingCredentials}
46 | *
47 | * @param request {@link NativeWebRequest} containing the JWY token
48 | * @return {@link AuditingCredentials}
49 | */
50 | AuditingCredentials toUserCredentials(NativeWebRequest request) {
51 |
52 | Claims claims = readClaimsFrom(request);
53 |
54 | if (Objects.isNull(claims)) {
55 | throw new HttpClientErrorException(HttpStatus.FORBIDDEN, "No claims found in request");
56 | }
57 |
58 | Long userid = jwtTokenProviderService.getLongValueFromClaim(JwtTokenProviderService.USER, claims)
59 | .orElseThrow(() -> new AuthenticationServiceException("No user id found in header"));
60 |
61 | Long bandWidthId = jwtTokenProviderService.getLongValueFromClaim(JwtTokenProviderService.BANDWIDTH_ID, claims)
62 | .orElseThrow(() -> new AuthenticationServiceException("No bandwidth id found in header"));
63 |
64 |
65 | return new AuditingCredentials(userid, bandWidthId);
66 | }
67 |
68 | /**
69 | * Return the claims object that is a request attribute
70 | */
71 | Claims readClaimsFrom(NativeWebRequest nativeWebRequest) {
72 | final String token = jwtTokenProviderService.readJwtTokenFromAuthorizationHeader(nativeWebRequest.getNativeRequest(HttpServletRequest.class));
73 | return jwtTokenProviderService.getClaimsFrom(token);
74 |
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/murray/communications/services/formatters/CustomDateFormatter.java:
--------------------------------------------------------------------------------
1 | package com.murray.communications.services.formatters;
2 |
3 | import java.time.format.DateTimeFormatter;
4 |
5 | /**
6 | * Handle all internal date formatting to covert from string to java.time.*
7 | */
8 | public interface CustomDateFormatter {
9 |
10 |
11 | /**
12 | * Return the {@link DateTimeFormatter} used for formatting
13 | * {@link java.time.LocalDate}
14 | *
15 | * @return {@link DateTimeFormatter}
16 | */
17 | DateTimeFormatter localDateFormatter();
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/murray/communications/services/formatters/impl/CustomDateFormatterImpl.java:
--------------------------------------------------------------------------------
1 | package com.murray.communications.services.formatters.impl;
2 |
3 | import com.murray.communications.services.formatters.CustomDateFormatter;
4 |
5 | import java.time.format.DateTimeFormatter;
6 |
7 | /**
8 | * {@inheritDoc}
9 | */
10 | public class CustomDateFormatterImpl implements CustomDateFormatter {
11 |
12 |
13 | private DateTimeFormatter localDateFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
14 |
15 | /**
16 | * {@inheritDoc}
17 | */
18 | @Override
19 | public DateTimeFormatter localDateFormatter() {
20 |
21 | return localDateFormatter;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/murray/communications/services/messages/Impl/BandwidthMessageSender.java:
--------------------------------------------------------------------------------
1 | package com.murray.communications.services.messages.Impl;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import com.murray.communications.domain.entities.messages.SmsMessage;
6 | import com.murray.communications.dtos.enums.MessageStatus;
7 | import com.murray.communications.domain.entities.messages.BandWidthCredentials;
8 | import com.murray.communications.exceptions.BandWidthException;
9 | import lombok.extern.slf4j.Slf4j;
10 | import okhttp3.*;
11 |
12 | import java.io.IOException;
13 | import java.time.LocalDate;
14 | import java.util.Arrays;
15 | import java.util.Hashtable;
16 | import java.util.Map;
17 |
18 |
19 | /**
20 | * Responsible for building the message HTTP request and handling the response
21 | */
22 | @Slf4j
23 | class BandwidthMessageSender {
24 |
25 | static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
26 | static final String HTTPS_MESSAGING_BANDWIDTH_COM_API_V_2_USERS_S_MESSAGES = "https://messaging.bandwidth.com/api/v2/users/%s/messages";
27 | private final ObjectMapper objectMapper;
28 |
29 | BandwidthMessageSender() {
30 | this.objectMapper = new ObjectMapper();
31 | }
32 |
33 | /**
34 | * Send {@link SmsMessage} to bandwidth messaging service for handling.
35 | *
36 | * @param smsMessage
37 | * @return
38 | */
39 | public int send(final SmsMessage smsMessage) throws BandWidthException {
40 |
41 |
42 | if (!smsMessage.getStatus().equals(MessageStatus.CREATED) || smsMessage.isDeleted()
43 | || smsMessage.getSendDate().isBefore(LocalDate.now())) {
44 | log.warn("Skip sending message:{} because status:{}", smsMessage.getId(), smsMessage.getStatus());
45 | throw new BandWidthException(String.format("Message %s not valid for processing ",smsMessage.getId()));
46 | }
47 |
48 | try {
49 |
50 | OkHttpClient client = new OkHttpClient();
51 |
52 | Request request = buildPost(smsMessage);
53 |
54 | Response response = client.newCall(request).execute();
55 | if (!response.isSuccessful()) {
56 | log.error("Error sending message:{} code:{} response:{}", smsMessage.getId(), response.code(), response.body().string());
57 | throw new BandWidthException("Error sending message", response.code(), response.body().string());
58 | }
59 | log.info("message successfully processed code:{}, response:{}", response.code(), response.body().string());
60 | return response.code();
61 |
62 | } catch (IOException e) {
63 | log.error("Issue sending message:{}", smsMessage.getId(), e);
64 | throw new BandWidthException("Error sending message", e);
65 | }
66 |
67 | }
68 |
69 | /**
70 | * Build http post request using the message and badwidth credientals
71 | *
72 | * @param smsMessage
73 | * @return Request
74 | * @throws JsonProcessingException
75 | */
76 | private Request buildPost(final SmsMessage smsMessage) throws JsonProcessingException {
77 |
78 | RequestBody body = RequestBody.create(JSON, toJson(smsMessage));
79 |
80 | String authorization = getAuthorization(smsMessage.getBandWidthCredentials().getMessageApi(), smsMessage.getBandWidthCredentials().getMessageSecret());
81 |
82 | Request request = new Request.Builder()
83 | .url(toUrl(smsMessage.getBandWidthCredentials()))
84 | .post(body)
85 | .addHeader("Content-Type", "application/json")
86 | .addHeader("Authorization", authorization)
87 | .addHeader("Accept", "*/*")
88 | .addHeader("Cache-Control", "no-cache")
89 | .addHeader("Host", "messaging.bandwidth.com")
90 | .addHeader("Accept-Encoding", "gzip, deflate")
91 | .addHeader("Content-Length", "200")
92 | .addHeader("Connection", "keep-alive")
93 | .addHeader("cache-control", "no-cache")
94 | .build();
95 |
96 | return request;
97 |
98 | }
99 |
100 | /**
101 | * Generate the basic authorisation header value used in the http header
102 | *
103 | * @param token
104 | * @param secret
105 | * @return
106 | */
107 | private String getAuthorization(String token, String secret) {
108 | return Credentials.basic(token, secret);
109 |
110 | }
111 |
112 |
113 | /**
114 | * Build the bandwidth url that is used for posting message
115 | *
116 | * @param bandWidthCredentials
117 | * @return
118 | */
119 | private String toUrl(BandWidthCredentials bandWidthCredentials) {
120 |
121 | return String.format(HTTPS_MESSAGING_BANDWIDTH_COM_API_V_2_USERS_S_MESSAGES, bandWidthCredentials.getDashboardAccountId());
122 | }
123 |
124 | /**
125 | * Converts the {@link SmsMessage} into json form that can be supported by bandwidth
126 | *
127 | * @param smsMessage
128 | * @return
129 | * @throws JsonProcessingException
130 | */
131 | private String toJson(SmsMessage smsMessage) throws JsonProcessingException {
132 |
133 | MapTo be completed!!!!!
19 | 20 |27 | 28 | 29 | 30 |
31 |