1+ /*
2+ * Copyright 2017-2022 Amazon.com,
3+ * Inc. or its affiliates. All Rights Reserved.
4+ *
5+ * Licensed under the Amazon Software License (the "License").
6+ * You may not use this file except in compliance with the
7+ * License. A copy of the License is located at
8+ *
9+ * http://aws.amazon.com/asl/
10+ *
11+ * or in the "license" file accompanying this file. This file is
12+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
13+ * CONDITIONS OF ANY KIND, express or implied. See the License
14+ * for the specific language governing permissions and
15+ * limitations under the License.
16+ */
17+
18+ package com .amazonaws .cognito .clientcontext .data ;
19+
20+ import java .util .Map ;
21+
22+ import org .json .JSONException ;
23+ import org .json .JSONObject ;
24+
25+ import com .amazonaws .cognito .clientcontext .datacollection .ContextDataAggregator ;
26+ import com .amazonaws .cognito .clientcontext .util .SignatureGenerator ;
27+
28+ import android .content .Context ;
29+ import android .util .Base64 ;
30+ import android .util .Log ;
31+
32+ /**
33+ * It provides the user context data that is sent to the server.
34+ */
35+ public class UserContextDataProvider {
36+
37+ private static final String TAG = UserContextDataProvider .class .getSimpleName ();
38+ public static final String VERSION = "ANDROID20171114" ;
39+
40+ private ContextDataAggregator aggregator ;
41+ private SignatureGenerator signatureGenerator ;
42+
43+ /**
44+ * Private class to store an instance. This is used to ensure a singleton
45+ * instance of the class.
46+ */
47+ private static class InstanceHolder {
48+ private static final UserContextDataProvider INSTANCE = new UserContextDataProvider ();
49+ }
50+
51+ private UserContextDataProvider () {
52+ this (ContextDataAggregator .getInstance (), new SignatureGenerator ());
53+ }
54+
55+ /**
56+ * Protected constructor to instantiate a class object for unit testing.
57+ */
58+ protected UserContextDataProvider (ContextDataAggregator aggregator , SignatureGenerator signatureGenerator ) {
59+ this .aggregator = aggregator ;
60+ this .signatureGenerator = signatureGenerator ;
61+ }
62+
63+ /**
64+ * @return instance of the class
65+ */
66+ public static UserContextDataProvider getInstance () {
67+ return InstanceHolder .INSTANCE ;
68+ }
69+
70+ /**
71+ * It gets aggregated user context data, adds signature to it and provides
72+ * it in Base64 encoded form. Final data is JSON object with 'signature' and
73+ * 'payload'. Payload is a JSON object that contains 'username',
74+ * 'userPoolId', 'timestamp' and 'contextData'.
75+ *
76+ * @param context
77+ * android application context
78+ * @param username
79+ * username for the user
80+ * @param userPoolId
81+ * cognito userpoolId for the application
82+ * @param signatureSecret
83+ * secret key used while generating signature. For now, this
84+ * would be application clientId.
85+ * @return base64 encoded userContextData.
86+ */
87+ public String getEncodedContextData (Context context , String username , String userPoolId , String signatureSecret ) {
88+ JSONObject jsonResponse = new JSONObject ();
89+
90+ try {
91+ final Map <String , String > contextData = aggregator .getAggregatedData (context );
92+ JSONObject payload = getJsonPayload (contextData , username , userPoolId );
93+ String payloadString = payload .toString ();
94+
95+ String signature = signatureGenerator .getSignature (payloadString , signatureSecret , VERSION );
96+ jsonResponse = getJsonResponse (payloadString , signature );
97+ return getEncodedResponse (jsonResponse );
98+ } catch (Exception e ) {
99+ Log .e (TAG , "Exception in creating JSON from context data" );
100+ return null ;
101+ }
102+ }
103+
104+ private JSONObject getJsonPayload (Map <String , String > contextData , String username , String userPoolId )
105+ throws JSONException {
106+ JSONObject payload = new JSONObject ();
107+ payload .put (ContextDataJsonKeys .CONTEXT_DATA , new JSONObject (contextData ));
108+ payload .put (ContextDataJsonKeys .USERNAME , username );
109+ payload .put (ContextDataJsonKeys .USER_POOL_ID , userPoolId );
110+ payload .put (ContextDataJsonKeys .TIMESTAMP_MILLI_SEC , getTimestamp ());
111+ return payload ;
112+ }
113+
114+ /**
115+ * Protected to allow overriding in unit test.
116+ */
117+ protected String getTimestamp () {
118+ return String .valueOf (System .currentTimeMillis ());
119+ }
120+
121+ private JSONObject getJsonResponse (String payload , String signature ) throws JSONException {
122+ JSONObject jsonResponse = new JSONObject ();
123+ jsonResponse .put (ContextDataJsonKeys .DATA_PAYLOAD , payload );
124+ jsonResponse .put (ContextDataJsonKeys .SIGNATURE , signature );
125+ jsonResponse .put (ContextDataJsonKeys .VERSION , UserContextDataProvider .VERSION );
126+ return jsonResponse ;
127+ }
128+
129+ /**
130+ * Protected to allow overriding in unit test. Base64 is part of AndroidSdk
131+ * which cannot be directly invoked in unit test.
132+ */
133+ protected String getEncodedResponse (JSONObject jsonResponse ) {
134+ byte [] responseBytes = jsonResponse .toString ().getBytes (ConfigurationConstant .DEFAULT_CHARSET );
135+ return Base64 .encodeToString (responseBytes , Base64 .DEFAULT );
136+ }
137+
138+ /**
139+ * Class defines constant keys that are used in JSON response object.
140+ */
141+ private class ContextDataJsonKeys {
142+ private static final String CONTEXT_DATA = "contextData" ;
143+ private static final String USERNAME = "username" ;
144+ private static final String USER_POOL_ID = "userPoolId" ;
145+ private static final String TIMESTAMP_MILLI_SEC = "timestamp" ;
146+ private static final String DATA_PAYLOAD = "payload" ;
147+ private static final String VERSION = "version" ;
148+ private static final String SIGNATURE = "signature" ;
149+ }
150+ }
0 commit comments