From 63d06b46c250ecba53b9548bd4ecc8f30c363370 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 19 Sep 2020 15:01:21 -0400 Subject: [PATCH 01/11] auth skeleton Include Amplify SDK, test basic auth functions, and setup framework for internal, synchronous interface. --- Listify/.gitignore | 16 + Listify/.idea/misc.xml | 2 +- Listify/amplify/.config/project-config.json | 13 + ...istifyf4fad454-cloudformation-template.yml | 396 ++++++++++++++++++ .../auth/listifyf4fad454/parameters.json | 60 +++ Listify/amplify/backend/backend-config.json | 10 + Listify/amplify/backend/tags.json | 10 + Listify/amplify/cli.json | 3 + Listify/amplify/team-provider-info.json | 20 + Listify/app/build.gradle | 10 + Listify/app/src/main/AndroidManifest.xml | 1 + .../java/com/example/listify/AuthManager.java | 88 ++++ .../java/com/example/listify/Listify.java | 20 + .../com/example/listify/MainActivity.java | 10 + 14 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 Listify/amplify/.config/project-config.json create mode 100644 Listify/amplify/backend/auth/listifyf4fad454/listifyf4fad454-cloudformation-template.yml create mode 100644 Listify/amplify/backend/auth/listifyf4fad454/parameters.json create mode 100644 Listify/amplify/backend/backend-config.json create mode 100644 Listify/amplify/backend/tags.json create mode 100644 Listify/amplify/cli.json create mode 100644 Listify/amplify/team-provider-info.json create mode 100644 Listify/app/src/main/java/com/example/listify/AuthManager.java create mode 100644 Listify/app/src/main/java/com/example/listify/Listify.java diff --git a/Listify/.gitignore b/Listify/.gitignore index 603b140..49b1255 100644 --- a/Listify/.gitignore +++ b/Listify/.gitignore @@ -12,3 +12,19 @@ /captures .externalNativeBuild .cxx + +#amplify +amplify/\#current-cloud-backend +amplify/.config/local-* +amplify/mock-data +amplify/backend/amplify-meta.json +amplify/backend/awscloudformation +build/ +dist/ +node_modules/ +aws-exports.js +awsconfiguration.json +amplifyconfiguration.json +amplify-build-config.json +amplify-gradle-config.json +amplifytools.xcconfig \ No newline at end of file diff --git a/Listify/.idea/misc.xml b/Listify/.idea/misc.xml index 892046b..fdae1d0 100644 --- a/Listify/.idea/misc.xml +++ b/Listify/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/Listify/amplify/.config/project-config.json b/Listify/amplify/.config/project-config.json new file mode 100644 index 0000000..a201d20 --- /dev/null +++ b/Listify/amplify/.config/project-config.json @@ -0,0 +1,13 @@ +{ + "projectName": "Listify", + "version": "3.0", + "frontend": "android", + "android": { + "config": { + "ResDir": "app/src/main/res" + } + }, + "providers": [ + "awscloudformation" + ] +} \ No newline at end of file diff --git a/Listify/amplify/backend/auth/listifyf4fad454/listifyf4fad454-cloudformation-template.yml b/Listify/amplify/backend/auth/listifyf4fad454/listifyf4fad454-cloudformation-template.yml new file mode 100644 index 0000000..95c418b --- /dev/null +++ b/Listify/amplify/backend/auth/listifyf4fad454/listifyf4fad454-cloudformation-template.yml @@ -0,0 +1,396 @@ +AWSTemplateFormatVersion: 2010-09-09 + +Parameters: + env: + Type: String + authRoleArn: + Type: String + unauthRoleArn: + Type: String + + + + + identityPoolName: + Type: String + + allowUnauthenticatedIdentities: + Type: String + + resourceNameTruncated: + Type: String + + userPoolName: + Type: String + + autoVerifiedAttributes: + Type: CommaDelimitedList + + mfaConfiguration: + Type: String + + mfaTypes: + Type: CommaDelimitedList + + smsAuthenticationMessage: + Type: String + + smsVerificationMessage: + Type: String + + emailVerificationSubject: + Type: String + + emailVerificationMessage: + Type: String + + defaultPasswordPolicy: + Type: String + + passwordPolicyMinLength: + Type: Number + + passwordPolicyCharacters: + Type: CommaDelimitedList + + requiredAttributes: + Type: CommaDelimitedList + + userpoolClientGenerateSecret: + Type: String + + userpoolClientRefreshTokenValidity: + Type: Number + + userpoolClientWriteAttributes: + Type: CommaDelimitedList + + userpoolClientReadAttributes: + Type: CommaDelimitedList + + userpoolClientLambdaRole: + Type: String + + userpoolClientSetAttributes: + Type: String + + sharedId: + Type: String + + resourceName: + Type: String + + authSelections: + Type: String + + useDefault: + Type: String + + usernameAttributes: + Type: CommaDelimitedList + + triggers: + Type: String + + userPoolGroupList: + Type: CommaDelimitedList + + serviceName: + Type: String + + parentStack: + Type: String + + permissions: + Type: CommaDelimitedList + + dependsOn: + Type: CommaDelimitedList + +Conditions: + ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ] + +Resources: + + + # BEGIN SNS ROLE RESOURCE + SNSRole: + # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process + Type: AWS::IAM::Role + Properties: + RoleName: !If [ShouldNotCreateEnvResources, 'listiff4fad454_sns-role', !Join ['',[ 'sns', 'f4fad454', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: "" + Effect: "Allow" + Principal: + Service: "cognito-idp.amazonaws.com" + Action: + - "sts:AssumeRole" + Condition: + StringEquals: + sts:ExternalId: listiff4fad454_role_external_id + Policies: + - + PolicyName: listiff4fad454-sns-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - + Effect: "Allow" + Action: + - "sns:Publish" + Resource: "*" + # BEGIN USER POOL RESOURCES + UserPool: + # Created upon user selection + # Depends on SNS Role for Arn if MFA is enabled + Type: AWS::Cognito::UserPool + UpdateReplacePolicy: Retain + Properties: + UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]] + + Schema: + + - + Name: email + Required: true + Mutable: true + + + + + AutoVerifiedAttributes: !Ref autoVerifiedAttributes + + + EmailVerificationMessage: !Ref emailVerificationMessage + EmailVerificationSubject: !Ref emailVerificationSubject + + Policies: + PasswordPolicy: + MinimumLength: !Ref passwordPolicyMinLength + RequireLowercase: false + RequireNumbers: false + RequireSymbols: false + RequireUppercase: false + + UsernameAttributes: !Ref usernameAttributes + + MfaConfiguration: !Ref mfaConfiguration + SmsVerificationMessage: !Ref smsVerificationMessage + SmsConfiguration: + SnsCallerArn: !GetAtt SNSRole.Arn + ExternalId: listiff4fad454_role_external_id + + + + + + + + + + + + # Updating lambda role with permissions to Cognito + + + UserPoolClientWeb: + # Created provide application access to user pool + # Depends on UserPool for ID reference + Type: "AWS::Cognito::UserPoolClient" + Properties: + ClientName: listiff4fad454_app_clientWeb + + RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity + UserPoolId: !Ref UserPool + DependsOn: UserPool + UserPoolClient: + # Created provide application access to user pool + # Depends on UserPool for ID reference + Type: "AWS::Cognito::UserPoolClient" + Properties: + ClientName: listiff4fad454_app_client + + GenerateSecret: !Ref userpoolClientGenerateSecret + RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity + UserPoolId: !Ref UserPool + DependsOn: UserPool + # BEGIN USER POOL LAMBDA RESOURCES + UserPoolClientRole: + # Created to execute Lambda which gets userpool app client config values + Type: 'AWS::IAM::Role' + Properties: + RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',['upClientLambdaRole', 'f4fad454', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - 'sts:AssumeRole' + DependsOn: UserPoolClient + UserPoolClientLambda: + # Lambda which gets userpool app client config values + # Depends on UserPool for id + # Depends on UserPoolClientRole for role ARN + Type: 'AWS::Lambda::Function' + Properties: + Code: + ZipFile: !Join + - |+ + - - 'const response = require(''cfn-response'');' + - 'const aws = require(''aws-sdk'');' + - 'const identity = new aws.CognitoIdentityServiceProvider();' + - 'exports.handler = (event, context, callback) => {' + - ' if (event.RequestType == ''Delete'') { ' + - ' response.send(event, context, response.SUCCESS, {})' + - ' }' + - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' + - ' const params = {' + - ' ClientId: event.ResourceProperties.clientId,' + - ' UserPoolId: event.ResourceProperties.userpoolId' + - ' };' + - ' identity.describeUserPoolClient(params).promise()' + - ' .then((res) => {' + - ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});' + - ' })' + - ' .catch((err) => {' + - ' response.send(event, context, response.FAILED, {err});' + - ' });' + - ' }' + - '};' + Handler: index.handler + Runtime: nodejs10.x + Timeout: '300' + Role: !GetAtt + - UserPoolClientRole + - Arn + DependsOn: UserPoolClientRole + UserPoolClientLambdaPolicy: + # Sets userpool policy for the role that executes the Userpool Client Lambda + # Depends on UserPool for Arn + # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: listiff4fad454_userpoolclient_lambda_iam_policy + Roles: + - !Ref UserPoolClientRole + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - 'cognito-idp:DescribeUserPoolClient' + Resource: !GetAtt UserPool.Arn + DependsOn: UserPoolClientLambda + UserPoolClientLogPolicy: + # Sets log policy for the role that executes the Userpool Client Lambda + # Depends on UserPool for Arn + # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: listiff4fad454_userpoolclient_lambda_log_policy + Roles: + - !Ref UserPoolClientRole + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'logs:CreateLogGroup' + - 'logs:CreateLogStream' + - 'logs:PutLogEvents' + Resource: !Sub + - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* + - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda} + DependsOn: UserPoolClientLambdaPolicy + UserPoolClientInputs: + # Values passed to Userpool client Lambda + # Depends on UserPool for Id + # Depends on UserPoolClient for Id + # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing + Type: 'Custom::LambdaCallout' + Properties: + ServiceToken: !GetAtt UserPoolClientLambda.Arn + clientId: !Ref UserPoolClient + userpoolId: !Ref UserPool + DependsOn: UserPoolClientLogPolicy + + + + + + + + # BEGIN IDENTITY POOL RESOURCES + + + IdentityPool: + # Always created + Type: AWS::Cognito::IdentityPool + Properties: + IdentityPoolName: !If [ShouldNotCreateEnvResources, 'listifyf4fad454_identitypool_f4fad454', !Join ['',['listifyf4fad454_identitypool_f4fad454', '__', !Ref env]]] + + CognitoIdentityProviders: + - ClientId: !Ref UserPoolClient + ProviderName: !Sub + - cognito-idp.${region}.amazonaws.com/${client} + - { region: !Ref "AWS::Region", client: !Ref UserPool} + - ClientId: !Ref UserPoolClientWeb + ProviderName: !Sub + - cognito-idp.${region}.amazonaws.com/${client} + - { region: !Ref "AWS::Region", client: !Ref UserPool} + + AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities + + + DependsOn: UserPoolClientInputs + + + IdentityPoolRoleMap: + # Created to map Auth and Unauth roles to the identity pool + # Depends on Identity Pool for ID ref + Type: AWS::Cognito::IdentityPoolRoleAttachment + Properties: + IdentityPoolId: !Ref IdentityPool + Roles: + unauthenticated: !Ref unauthRoleArn + authenticated: !Ref authRoleArn + DependsOn: IdentityPool + + +Outputs : + + IdentityPoolId: + Value: !Ref 'IdentityPool' + Description: Id for the identity pool + IdentityPoolName: + Value: !GetAtt IdentityPool.Name + + + + + UserPoolId: + Value: !Ref 'UserPool' + Description: Id for the user pool + UserPoolName: + Value: !Ref userPoolName + AppClientIDWeb: + Value: !Ref 'UserPoolClientWeb' + Description: The user pool app client id for web + AppClientID: + Value: !Ref 'UserPoolClient' + Description: The user pool app client id + AppClientSecret: + Value: !GetAtt UserPoolClientInputs.appSecret + + + + + + + diff --git a/Listify/amplify/backend/auth/listifyf4fad454/parameters.json b/Listify/amplify/backend/auth/listifyf4fad454/parameters.json new file mode 100644 index 0000000..1118f10 --- /dev/null +++ b/Listify/amplify/backend/auth/listifyf4fad454/parameters.json @@ -0,0 +1,60 @@ +{ + "identityPoolName": "listifyf4fad454_identitypool_f4fad454", + "allowUnauthenticatedIdentities": false, + "resourceNameTruncated": "listiff4fad454", + "userPoolName": "listifyf4fad454_userpool_f4fad454", + "autoVerifiedAttributes": [ + "email" + ], + "mfaConfiguration": "OFF", + "mfaTypes": [ + "SMS Text Message" + ], + "smsAuthenticationMessage": "Your authentication code is {####}", + "smsVerificationMessage": "Your verification code is {####}", + "emailVerificationSubject": "Your verification code", + "emailVerificationMessage": "Your verification code is {####}", + "defaultPasswordPolicy": false, + "passwordPolicyMinLength": 8, + "passwordPolicyCharacters": [], + "requiredAttributes": [ + "email" + ], + "userpoolClientGenerateSecret": true, + "userpoolClientRefreshTokenValidity": 30, + "userpoolClientWriteAttributes": [ + "email" + ], + "userpoolClientReadAttributes": [ + "email" + ], + "userpoolClientLambdaRole": "listiff4fad454_userpoolclient_lambda_role", + "userpoolClientSetAttributes": false, + "sharedId": "f4fad454", + "resourceName": "listifyf4fad454", + "authSelections": "identityPoolAndUserPool", + "authRoleArn": { + "Fn::GetAtt": [ + "AuthRole", + "Arn" + ] + }, + "unauthRoleArn": { + "Fn::GetAtt": [ + "UnauthRole", + "Arn" + ] + }, + "useDefault": "default", + "usernameAttributes": [ + "email" + ], + "triggers": "{}", + "userPoolGroupList": [], + "serviceName": "Cognito", + "parentStack": { + "Ref": "AWS::StackId" + }, + "permissions": [], + "dependsOn": [] +} \ No newline at end of file diff --git a/Listify/amplify/backend/backend-config.json b/Listify/amplify/backend/backend-config.json new file mode 100644 index 0000000..8b34cae --- /dev/null +++ b/Listify/amplify/backend/backend-config.json @@ -0,0 +1,10 @@ +{ + "auth": { + "listifyf4fad454": { + "service": "Cognito", + "providerPlugin": "awscloudformation", + "dependsOn": [], + "customAuth": false + } + } +} \ No newline at end of file diff --git a/Listify/amplify/backend/tags.json b/Listify/amplify/backend/tags.json new file mode 100644 index 0000000..b9321d7 --- /dev/null +++ b/Listify/amplify/backend/tags.json @@ -0,0 +1,10 @@ +[ + { + "Key": "user:Stack", + "Value": "{project-env}" + }, + { + "Key": "user:Application", + "Value": "{project-name}" + } +] \ No newline at end of file diff --git a/Listify/amplify/cli.json b/Listify/amplify/cli.json new file mode 100644 index 0000000..876a6e2 --- /dev/null +++ b/Listify/amplify/cli.json @@ -0,0 +1,3 @@ +{ + "features": {} +} \ No newline at end of file diff --git a/Listify/amplify/team-provider-info.json b/Listify/amplify/team-provider-info.json new file mode 100644 index 0000000..2ff66cd --- /dev/null +++ b/Listify/amplify/team-provider-info.json @@ -0,0 +1,20 @@ +{ + "dev": { + "awscloudformation": { + "AuthRoleName": "amplify-listify-dev-134836-authRole", + "UnauthRoleArn": "arn:aws:iam::569815541706:role/amplify-listify-dev-134836-unauthRole", + "AuthRoleArn": "arn:aws:iam::569815541706:role/amplify-listify-dev-134836-authRole", + "Region": "us-east-2", + "DeploymentBucketName": "amplify-listify-dev-134836-deployment", + "UnauthRoleName": "amplify-listify-dev-134836-unauthRole", + "StackName": "amplify-listify-dev-134836", + "StackId": "arn:aws:cloudformation:us-east-2:569815541706:stack/amplify-listify-dev-134836/5980b520-faa0-11ea-a89c-0650659cf0f8", + "AmplifyAppId": "dbnznhwtkbqz6" + }, + "categories": { + "auth": { + "listifyf4fad454": {} + } + } + } +} \ No newline at end of file diff --git a/Listify/app/build.gradle b/Listify/app/build.gradle index f56ecf1..4e13596 100644 --- a/Listify/app/build.gradle +++ b/Listify/app/build.gradle @@ -14,6 +14,13 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + compileOptions { + // Support for Java 8 features + coreLibraryDesugaringEnabled true + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildTypes { release { minifyEnabled false @@ -34,5 +41,8 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + implementation 'com.amplifyframework:core:1.3.2' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10' + implementation 'com.amplifyframework:aws-auth-cognito:1.3.2' } \ No newline at end of file diff --git a/Listify/app/src/main/AndroidManifest.xml b/Listify/app/src/main/AndroidManifest.xml index 7672ac7..3c75eac 100644 --- a/Listify/app/src/main/AndroidManifest.xml +++ b/Listify/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="com.example.listify"> setAuthSession(result), + error -> setAuthError(error) + ); + throwIfAuthError(); + } + + + public void setAuthSession(AuthSession toSet) { + authSession = toSet; + } + + public void setAuthError(AuthException newError) { + authError = newError; + waiting = false; + } + + public void throwIfAuthError() throws AuthException{ + while (waiting); + if (authError == null) { + return; + } + AuthException toThrow = authError; + authError = null; + throw toThrow; + } + + public void setAuthSignUpResult(AuthSignUpResult toSet) { + authSignUpResult = toSet; + } + + public void startSignup(String email, String password) throws AuthException { + this.email = email; + this.password = password; + waiting = true; + Amplify.Auth.signUp( + email, + password, + AuthSignUpOptions.builder().build(), + result -> setAuthSignUpResult(result), + error -> setAuthError(error) + ); + throwIfAuthError(); + + } + + public void confirmSignUp(String confirmationCode) { + Amplify.Auth.confirmSignUp( + email, + confirmationCode, + result -> Log.i("AuthQuickstart", result.isSignUpComplete() ? "Confirm signUp succeeded" : "Confirm sign up not complete"), + error -> Log.e("AuthQuickstart", error.toString()) + ); + } + + public void signIn(String email, String password) { + Amplify.Auth.signIn( + email, + password, + result -> Log.i("AuthQuickstart", result.isSignInComplete() ? "Sign in succeeded" : "Sign in not complete"), + error -> Log.e("AuthQuickstart", error.toString()) + ); + } + + + + +} diff --git a/Listify/app/src/main/java/com/example/listify/Listify.java b/Listify/app/src/main/java/com/example/listify/Listify.java new file mode 100644 index 0000000..20e6d11 --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/Listify.java @@ -0,0 +1,20 @@ +package com.example.listify; + +import android.util.Log; +import com.amplifyframework.AmplifyException; +import com.amplifyframework.auth.cognito.AWSCognitoAuthPlugin; +import com.amplifyframework.core.Amplify; + +public class Listify extends android.app.Application { + public void onCreate() { + super.onCreate(); + + try { + Amplify.addPlugin(new AWSCognitoAuthPlugin()); + Amplify.configure(getApplicationContext()); + Log.i("MyAmplifyApp", "Initialized Amplify"); + } catch (AmplifyException error) { + Log.e("MyAmplifyApp", "Could not initialize Amplify", error); + } + } +} diff --git a/Listify/app/src/main/java/com/example/listify/MainActivity.java b/Listify/app/src/main/java/com/example/listify/MainActivity.java index f63de5b..3145a02 100644 --- a/Listify/app/src/main/java/com/example/listify/MainActivity.java +++ b/Listify/app/src/main/java/com/example/listify/MainActivity.java @@ -1,9 +1,13 @@ package com.example.listify; import android.os.Bundle; +import android.util.Log; import android.view.View; import android.view.Menu; +import com.amplifyframework.auth.AuthUserAttributeKey; +import com.amplifyframework.auth.options.AuthSignUpOptions; +import com.amplifyframework.core.Amplify; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import com.google.android.material.navigation.NavigationView; @@ -23,6 +27,12 @@ public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + //------------------------------Auth Testing---------------------------------------------// + + + + + //------------------------------------------------------------------------------------------// setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); From 2b1ecbadef925832c333602e8c8c786f6ccfbaf7 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 20 Sep 2020 10:38:08 -0400 Subject: [PATCH 02/11] Finish conversion to synchronized methods Finished setting callbacks and made waiting volatile so cached value is not used across threads. --- .../java/com/example/listify/AuthManager.java | 37 ++++++++++++++----- .../com/example/listify/MainActivity.java | 15 ++++++++ 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/Listify/app/src/main/java/com/example/listify/AuthManager.java b/Listify/app/src/main/java/com/example/listify/AuthManager.java index 0a0c443..5ac6563 100644 --- a/Listify/app/src/main/java/com/example/listify/AuthManager.java +++ b/Listify/app/src/main/java/com/example/listify/AuthManager.java @@ -4,19 +4,21 @@ import android.util.Log; import com.amplifyframework.auth.AuthException; import com.amplifyframework.auth.AuthSession; import com.amplifyframework.auth.options.AuthSignUpOptions; +import com.amplifyframework.auth.result.AuthSignInResult; import com.amplifyframework.auth.result.AuthSignUpResult; import com.amplifyframework.core.Amplify; public class AuthManager { AuthSession authSession = null; AuthSignUpResult authSignUpResult = null; + AuthSignInResult authSignInResult = null; AuthException authError = null; String email = null; String password = null; - boolean waiting = false; + volatile boolean waiting = false; - public void fetchAuthSession() throws AuthException { + void fetchAuthSession() throws AuthException { waiting = true; Amplify.Auth.fetchAuthSession( result -> setAuthSession(result), @@ -25,9 +27,15 @@ public class AuthManager { throwIfAuthError(); } + public AuthSession getAuthSession() throws AuthException { + fetchAuthSession(); + return authSession; + } + public void setAuthSession(AuthSession toSet) { authSession = toSet; + waiting = false; } public void setAuthError(AuthException newError) { @@ -49,7 +57,12 @@ public class AuthManager { authSignUpResult = toSet; } - public void startSignup(String email, String password) throws AuthException { + public void setAuthSignInResult(AuthSignInResult toSet) { + authSignInResult = toSet; + waiting = false; + } + + public void startSignUp(String email, String password) throws AuthException { this.email = email; this.password = password; waiting = true; @@ -64,22 +77,28 @@ public class AuthManager { } - public void confirmSignUp(String confirmationCode) { + public void confirmSignUp(String confirmationCode) throws AuthException { + waiting = true; Amplify.Auth.confirmSignUp( email, confirmationCode, - result -> Log.i("AuthQuickstart", result.isSignUpComplete() ? "Confirm signUp succeeded" : "Confirm sign up not complete"), - error -> Log.e("AuthQuickstart", error.toString()) + result -> setAuthSignUpResult(result), + error -> setAuthError(error) ); + throwIfAuthError(); } - public void signIn(String email, String password) { + public void signIn(String email, String password) throws AuthException{ + this.email = email; + this.password = password; + waiting = true; Amplify.Auth.signIn( email, password, - result -> Log.i("AuthQuickstart", result.isSignInComplete() ? "Sign in succeeded" : "Sign in not complete"), - error -> Log.e("AuthQuickstart", error.toString()) + result -> setAuthSignInResult(result), + error -> setAuthError(error) ); + throwIfAuthError(); } diff --git a/Listify/app/src/main/java/com/example/listify/MainActivity.java b/Listify/app/src/main/java/com/example/listify/MainActivity.java index 3145a02..12e7312 100644 --- a/Listify/app/src/main/java/com/example/listify/MainActivity.java +++ b/Listify/app/src/main/java/com/example/listify/MainActivity.java @@ -5,6 +5,8 @@ import android.util.Log; import android.view.View; import android.view.Menu; +import com.amazonaws.mobileconnectors.cognitoauth.Auth; +import com.amplifyframework.auth.AuthException; import com.amplifyframework.auth.AuthUserAttributeKey; import com.amplifyframework.auth.options.AuthSignUpOptions; import com.amplifyframework.core.Amplify; @@ -29,6 +31,19 @@ public class MainActivity extends AppCompatActivity { super.onCreate(savedInstanceState); //------------------------------Auth Testing---------------------------------------------// + AuthManager authManager = new AuthManager(); + try { + authManager.signIn("merzn@purdue.edu", "Password123"); + Log.i("Authentication", authManager.getAuthSession().toString()); + } catch (AuthException e) { + Log.i("Authentication", "Login failed. User probably needs to register. Exact error: " + e.getMessage()); + try { + authManager.startSignUp("merzn@purdue.edu", "Password123"); + authManager.confirmSignUp("######"); + } catch (AuthException signUpError) { + Log.e("Authentication", "SignUp error: " + signUpError.getMessage()); + } + } From f576307e0a112ef2bdee7b650e2ba580d9288473 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 20 Sep 2020 16:26:13 -0400 Subject: [PATCH 03/11] Set up initial Lambda sturucture with Cognito Create demo Lambda/Gateway pair with Cognito integration --- .gitignore | 1 + Lambdas/Lists/pom.xml | 28 +++++++++++++ Lambdas/Lists/src/main/java/ListAdd.java | 22 ++++++++++ Listify/Pipfile | 11 +++++ ...istifyf4fad454-cloudformation-template.yml | 2 +- .../auth/listifyf4fad454/parameters.json | 2 +- Listify/amplify/backend/backend-config.json | 4 +- .../java/com/example/listify/AuthManager.java | 17 +++++--- .../com/example/listify/MainActivity.java | 1 + Tooling/EndpointSetup.sh | 42 +++++++++++++++++++ Tooling/aws_method_request_passthrough.json | 7 ++++ 11 files changed, 129 insertions(+), 8 deletions(-) create mode 100644 Lambdas/Lists/pom.xml create mode 100644 Lambdas/Lists/src/main/java/ListAdd.java create mode 100644 Listify/Pipfile create mode 100644 Tooling/EndpointSetup.sh create mode 100644 Tooling/aws_method_request_passthrough.json diff --git a/.gitignore b/.gitignore index 56cc642..f0a7210 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ captures/ .idea/assetWizardSettings.xml .idea/dictionaries .idea/libraries +*.idea* # Android Studio 3 in .gitignore file. .idea/caches .idea/modules.xml diff --git a/Lambdas/Lists/pom.xml b/Lambdas/Lists/pom.xml new file mode 100644 index 0000000..2c6ea85 --- /dev/null +++ b/Lambdas/Lists/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + groupId + Lists + 1.0-SNAPSHOT + + + + com.amazonaws + aws-lambda-java-core + 1.2.1 + + + com.amazonaws + aws-lambda-java-events + 3.1.0 + + + com.amazonaws + aws-lambda-java-log4j2 + 1.2.0 + + + \ No newline at end of file diff --git a/Lambdas/Lists/src/main/java/ListAdd.java b/Lambdas/Lists/src/main/java/ListAdd.java new file mode 100644 index 0000000..fe0354b --- /dev/null +++ b/Lambdas/Lists/src/main/java/ListAdd.java @@ -0,0 +1,22 @@ +import java.util.Map; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +public class ListAdd implements RequestHandler, String>{ + + + public String handleRequest(Map inputMap, Context unfilled) { + System.out.println(inputMap.keySet()); + System.out.println(inputMap.entrySet()); + Map contextMap; + if ((inputMap.get("context") != null) && (inputMap.get("context") instanceof Map)) { + contextMap = ((Map) inputMap.get("context")); + } else { + throw new IllegalArgumentException("The key \"Context\" must exist and be a map"); + } + System.out.println(inputMap.get("context")); + System.out.println(contextMap.get("sub")); + return null; + } +} diff --git a/Listify/Pipfile b/Listify/Pipfile new file mode 100644 index 0000000..b5846df --- /dev/null +++ b/Listify/Pipfile @@ -0,0 +1,11 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] + +[requires] +python_version = "3.8" diff --git a/Listify/amplify/backend/auth/listifyf4fad454/listifyf4fad454-cloudformation-template.yml b/Listify/amplify/backend/auth/listifyf4fad454/listifyf4fad454-cloudformation-template.yml index 95c418b..8560fdb 100644 --- a/Listify/amplify/backend/auth/listifyf4fad454/listifyf4fad454-cloudformation-template.yml +++ b/Listify/amplify/backend/auth/listifyf4fad454/listifyf4fad454-cloudformation-template.yml @@ -94,7 +94,7 @@ Parameters: userPoolGroupList: Type: CommaDelimitedList - + serviceName: Type: String diff --git a/Listify/amplify/backend/auth/listifyf4fad454/parameters.json b/Listify/amplify/backend/auth/listifyf4fad454/parameters.json index 1118f10..8c6f1d6 100644 --- a/Listify/amplify/backend/auth/listifyf4fad454/parameters.json +++ b/Listify/amplify/backend/auth/listifyf4fad454/parameters.json @@ -1,6 +1,6 @@ { "identityPoolName": "listifyf4fad454_identitypool_f4fad454", - "allowUnauthenticatedIdentities": false, + "allowUnauthenticatedIdentities": true, "resourceNameTruncated": "listiff4fad454", "userPoolName": "listifyf4fad454_userpool_f4fad454", "autoVerifiedAttributes": [ diff --git a/Listify/amplify/backend/backend-config.json b/Listify/amplify/backend/backend-config.json index 8b34cae..771cac6 100644 --- a/Listify/amplify/backend/backend-config.json +++ b/Listify/amplify/backend/backend-config.json @@ -6,5 +6,7 @@ "dependsOn": [], "customAuth": false } - } + }, + "function": {}, + "api": {} } \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/AuthManager.java b/Listify/app/src/main/java/com/example/listify/AuthManager.java index 5ac6563..637cb3c 100644 --- a/Listify/app/src/main/java/com/example/listify/AuthManager.java +++ b/Listify/app/src/main/java/com/example/listify/AuthManager.java @@ -1,15 +1,15 @@ package com.example.listify; -import android.util.Log; import com.amplifyframework.auth.AuthException; import com.amplifyframework.auth.AuthSession; +import com.amplifyframework.auth.cognito.AWSCognitoAuthSession; import com.amplifyframework.auth.options.AuthSignUpOptions; import com.amplifyframework.auth.result.AuthSignInResult; import com.amplifyframework.auth.result.AuthSignUpResult; import com.amplifyframework.core.Amplify; public class AuthManager { - AuthSession authSession = null; + AWSCognitoAuthSession authSession = null; AuthSignUpResult authSignUpResult = null; AuthSignInResult authSignInResult = null; AuthException authError = null; @@ -27,14 +27,21 @@ public class AuthManager { throwIfAuthError(); } - public AuthSession getAuthSession() throws AuthException { - fetchAuthSession(); + public AWSCognitoAuthSession getAuthSession() throws AuthException { + if (authSession == null) { + fetchAuthSession(); + } + return authSession; } + public String getUserToken() { + return authSession.getUserPoolTokens().getValue().getIdToken(); + } + public void setAuthSession(AuthSession toSet) { - authSession = toSet; + authSession = (AWSCognitoAuthSession) toSet; waiting = false; } diff --git a/Listify/app/src/main/java/com/example/listify/MainActivity.java b/Listify/app/src/main/java/com/example/listify/MainActivity.java index 12e7312..a24c00a 100644 --- a/Listify/app/src/main/java/com/example/listify/MainActivity.java +++ b/Listify/app/src/main/java/com/example/listify/MainActivity.java @@ -35,6 +35,7 @@ public class MainActivity extends AppCompatActivity { try { authManager.signIn("merzn@purdue.edu", "Password123"); Log.i("Authentication", authManager.getAuthSession().toString()); + Log.i("Token", authManager.getAuthSession().getUserPoolTokens().getValue().getIdToken()); } catch (AuthException e) { Log.i("Authentication", "Login failed. User probably needs to register. Exact error: " + e.getMessage()); try { diff --git a/Tooling/EndpointSetup.sh b/Tooling/EndpointSetup.sh new file mode 100644 index 0000000..4588a3f --- /dev/null +++ b/Tooling/EndpointSetup.sh @@ -0,0 +1,42 @@ +#Base script from: https://github.com/NMerz/DoctorsNote/blob/master/AWS%20Setup/Lambda-GatewayInitialization.sh + +#NOTE: This has been tested and works; however, the apigateway does not properly show as a trigger in AWS's web UI +#NOTE2: This assumes that the root Gateway and Lambda role have been set up previously (one-time setup) and their values are store in the constants below + +#constants +APIID=datoh7woc9 #rest-api-id is tied to the apigateway while resource-id seems tied to the specific url extension +ROOTRESOURCEID=6xrzhzidxh #gateway root should have a consistent resource id which will serve as parent for many apis +LAMBDAROLE=arn:aws:iam::569815541706:role/LambdaBasic +LANGUAGE=java11 +DEPLOYSTAGE=Development + +DEBUGFILE=/dev/null + +echo -n "Please enter function name: " +read functionName +echo -n "Please enter path to zip of function code: " +read functionPath +echo -n "Please enter url extension: " +read partName + +LAMBDAARN=$(aws lambda create-function --function-name ${functionName} --zip-file fileb://${functionPath} --runtime ${LANGUAGE} --role ${LAMBDAROLE} --handler ${functionName}.lambda_handler | head -n 3 | tail -n 1 | cut -d \" -f 4) + +echo ${LAMBDAARN} > ${DEBUGFILE} + +RESOURCEID=$(aws apigateway create-resource --rest-api-id ${APIID} --parent-id ${ROOTRESOURCEID} --path-part ${partName} | head -n 2 | tail -n 1 | cut -d \" -f 4) + +echo ${RESOURCEID} > ${DEBUGFILE} + +aws apigateway put-method --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method POST --authorization-type COGNITO_USER_POOLS --authorizer-id awt4cs --api-key-required > ${DEBUGFILE} + +aws apigateway put-integration --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method POST --type AWS --integration-http-method POST --uri arn:aws:apigateway:us-east-2:lambda:path/2015-03-31/functions/${LAMBDAARN}/invocations > ${DEBUGFILE} + +aws lambda add-permission --function-name ${functionName} --statement-id ${functionName}API --action lambda:InvokeFunction --principal apigateway.amazonaws.com > ${DEBUGFILE} + +aws apigateway put-method-response --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method POST --status-code 200 > ${DEBUGFILE} + +aws apigateway put-integration-response --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method POST --status-code 200 --selection-pattern "" > ${DEBUGFILE} + +aws apigateway create-deployment --rest-api-id ${APIID} --stage-name ${DEPLOYSTAGE} --description "Deployment by creation script for function ${functionName}" > ${DEBUGFILE} + + diff --git a/Tooling/aws_method_request_passthrough.json b/Tooling/aws_method_request_passthrough.json new file mode 100644 index 0000000..efea7ce --- /dev/null +++ b/Tooling/aws_method_request_passthrough.json @@ -0,0 +1,7 @@ +{ + "body": $input.json('$'), + "context" : { + "sub" : "$context.authorizer.claims.sub", + "email" : "$context.authorizer.claims.email" + } +} \ No newline at end of file From 74eeb2a09dbc85be8efa1cf0a6e4327873b5c596 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 20 Sep 2020 23:33:36 -0400 Subject: [PATCH 04/11] Start Lambda connection infrastructure --- .gitignore | 1 + Lambdas/Lists/pom.xml | 14 ++++++++ Lambdas/Lists/src/main/java/DBConnector.java | 32 +++++++++++++++++++ Lambdas/Lists/src/main/java/ListAdd.java | 9 ++++++ Lambdas/Lists/src/main/java/ListAdder.java | 4 +++ .../Lists/target/classes/dbProperties.json | 5 +++ 6 files changed, 65 insertions(+) create mode 100644 Lambdas/Lists/src/main/java/DBConnector.java create mode 100644 Lambdas/Lists/src/main/java/ListAdder.java create mode 100644 Lambdas/Lists/target/classes/dbProperties.json diff --git a/.gitignore b/.gitignore index f0a7210..2fc6ec6 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,4 @@ lint/generated/ lint/outputs/ lint/tmp/ # lint/reports/ +Lambdas/Lists/src/main/resources/dbProperties.json diff --git a/Lambdas/Lists/pom.xml b/Lambdas/Lists/pom.xml index 2c6ea85..9442b49 100644 --- a/Lambdas/Lists/pom.xml +++ b/Lambdas/Lists/pom.xml @@ -24,5 +24,19 @@ aws-lambda-java-log4j2 1.2.0 + + org.json + json + 20200518 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + 1.11 + 1.11 + \ No newline at end of file diff --git a/Lambdas/Lists/src/main/java/DBConnector.java b/Lambdas/Lists/src/main/java/DBConnector.java new file mode 100644 index 0000000..c4f85b9 --- /dev/null +++ b/Lambdas/Lists/src/main/java/DBConnector.java @@ -0,0 +1,32 @@ +import org.json.JSONObject; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +public class DBConnector { + + Connection connection; + + DBConnector() throws IOException, SQLException { + this(loadProperties("dbProperties.json")); + } + + DBConnector(Properties dbProperties) throws SQLException { + System.out.println(dbProperties); + connection = DriverManager.getConnection(dbProperties.get("url").toString(), dbProperties); + + } + + public static Properties loadProperties(String path) throws IOException { + Properties toReturn = new Properties(); + String propertiesJSONString = Files.readString(Path.of(path)); + JSONObject propertiesJSON = new JSONObject(propertiesJSONString); + propertiesJSON.keys().forEachRemaining(key -> toReturn.setProperty(key, propertiesJSON.get(key).toString())); + return toReturn; + } +} diff --git a/Lambdas/Lists/src/main/java/ListAdd.java b/Lambdas/Lists/src/main/java/ListAdd.java index fe0354b..d5a698b 100644 --- a/Lambdas/Lists/src/main/java/ListAdd.java +++ b/Lambdas/Lists/src/main/java/ListAdd.java @@ -1,3 +1,5 @@ +import java.io.IOException; +import java.sql.SQLException; import java.util.Map; import com.amazonaws.services.lambda.runtime.Context; @@ -17,6 +19,13 @@ public class ListAdd implements RequestHandler, String>{ } System.out.println(inputMap.get("context")); System.out.println(contextMap.get("sub")); + try { + System.out.println(new DBConnector()); + } catch (IOException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } return null; } } diff --git a/Lambdas/Lists/src/main/java/ListAdder.java b/Lambdas/Lists/src/main/java/ListAdder.java new file mode 100644 index 0000000..413b7db --- /dev/null +++ b/Lambdas/Lists/src/main/java/ListAdder.java @@ -0,0 +1,4 @@ +public class ListAdder { + + +} diff --git a/Lambdas/Lists/target/classes/dbProperties.json b/Lambdas/Lists/target/classes/dbProperties.json new file mode 100644 index 0000000..ba1352b --- /dev/null +++ b/Lambdas/Lists/target/classes/dbProperties.json @@ -0,0 +1,5 @@ +{ + "url": "http://aws.com/something", + "user": "aUser", + "password": "aPassword" +} \ No newline at end of file From 34ed7358c5df0c2242525d9c7568063315d50b01 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 20 Sep 2020 23:33:55 -0400 Subject: [PATCH 05/11] Port tooling and increase durability --- Tooling/EndpointSetup.sh | 63 ++++++++++++++------- Tooling/aws_method_request_passthrough.json | 7 --- Tooling/body_and_auth_mapping.json | 3 + 3 files changed, 47 insertions(+), 26 deletions(-) delete mode 100644 Tooling/aws_method_request_passthrough.json create mode 100644 Tooling/body_and_auth_mapping.json diff --git a/Tooling/EndpointSetup.sh b/Tooling/EndpointSetup.sh index 4588a3f..81c2d08 100644 --- a/Tooling/EndpointSetup.sh +++ b/Tooling/EndpointSetup.sh @@ -1,7 +1,8 @@ +#!/bin/bash #Base script from: https://github.com/NMerz/DoctorsNote/blob/master/AWS%20Setup/Lambda-GatewayInitialization.sh #NOTE: This has been tested and works; however, the apigateway does not properly show as a trigger in AWS's web UI -#NOTE2: This assumes that the root Gateway and Lambda role have been set up previously (one-time setup) and their values are store in the constants below +#NOTE2: This assumes that the root Gateway and Lambda role have been set up previously (one-time setup) and their values are stored in the constants below #constants APIID=datoh7woc9 #rest-api-id is tied to the apigateway while resource-id seems tied to the specific url extension @@ -12,31 +13,55 @@ DEPLOYSTAGE=Development DEBUGFILE=/dev/null -echo -n "Please enter function name: " +echo -n "Please enter function/endpoint name: " read functionName -echo -n "Please enter path to zip of function code: " -read functionPath -echo -n "Please enter url extension: " -read partName +echo -n "Please enter method(GET, POST, etc.): " +read method -LAMBDAARN=$(aws lambda create-function --function-name ${functionName} --zip-file fileb://${functionPath} --runtime ${LANGUAGE} --role ${LAMBDAROLE} --handler ${functionName}.lambda_handler | head -n 3 | tail -n 1 | cut -d \" -f 4) +jarPath=$(find .. -name "${functionName}.jar") +if [[ "$jarPath" == "" ]]; then + echo "Unable to find file ${functionName}.jar" >&2 + exit 1 +fi +functionPath=${jarPath%/${functionName}.jar} +zipPath=${functionPath}.zip + +zip ${zipPath} ${jarPath} + +RAWLAMBDA=$(aws lambda create-function --function-name ${functionName}${method} --zip-file fileb://${zipPath} --runtime ${LANGUAGE} --role ${LAMBDAROLE} --handler ${functionName}.lambda_handler) + +if [[ $? -ne 0 ]]; then + echo "Unable to create Lamba" >&2 + exit 1 +fi + +LAMBDAARN=$(echo $RAWLAMBDA | head -n 3 | tail -n 1 | cut -d \" -f 8) echo ${LAMBDAARN} > ${DEBUGFILE} -RESOURCEID=$(aws apigateway create-resource --rest-api-id ${APIID} --parent-id ${ROOTRESOURCEID} --path-part ${partName} | head -n 2 | tail -n 1 | cut -d \" -f 4) +RAWRESOURCEID=$(aws apigateway create-resource --rest-api-id ${APIID} --parent-id ${ROOTRESOURCEID} --path-part ${functionName}) + +if [[ $? -ne 0 ]]; then + echo "Unable to create Resource. This needs to be handled at some future point" >&2 + exit 1 +fi + +RESOURCEID=$(echo ${RAWRESOURCEID} | head -n 2 | tail -n 1 | cut -d \" -f 4) echo ${RESOURCEID} > ${DEBUGFILE} -aws apigateway put-method --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method POST --authorization-type COGNITO_USER_POOLS --authorizer-id awt4cs --api-key-required > ${DEBUGFILE} - -aws apigateway put-integration --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method POST --type AWS --integration-http-method POST --uri arn:aws:apigateway:us-east-2:lambda:path/2015-03-31/functions/${LAMBDAARN}/invocations > ${DEBUGFILE} - -aws lambda add-permission --function-name ${functionName} --statement-id ${functionName}API --action lambda:InvokeFunction --principal apigateway.amazonaws.com > ${DEBUGFILE} - -aws apigateway put-method-response --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method POST --status-code 200 > ${DEBUGFILE} - -aws apigateway put-integration-response --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method POST --status-code 200 --selection-pattern "" > ${DEBUGFILE} - -aws apigateway create-deployment --rest-api-id ${APIID} --stage-name ${DEPLOYSTAGE} --description "Deployment by creation script for function ${functionName}" > ${DEBUGFILE} +aws apigateway put-method --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method ${method} --authorization-type COGNITO_USER_POOLS --authorizer-id awt4cs --api-key-required > ${DEBUGFILE} + + + +aws apigateway put-integration --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method ${method} --type AWS --integration-http-method POST --uri arn:aws:apigateway:us-east-2:lambda:path/2015-03-31/functions/${LAMBDAARN}/invocations --request-templates 'file://body_and_auth_mapping.json' > ${DEBUGFILE} + +aws lambda add-permission --function-name ${functionName}${method} --statement-id ${functionName}API --action lambda:InvokeFunction --principal apigateway.amazonaws.com > ${DEBUGFILE} + +aws apigateway put-method-response --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method ${method} --status-code 200 > ${DEBUGFILE} + +aws apigateway put-integration-response --rest-api-id ${APIID} --resource-id ${RESOURCEID} --http-method ${method} --status-code 200 --selection-pattern "" > ${DEBUGFILE} + +aws apigateway create-deployment --rest-api-id ${APIID} --stage-name ${DEPLOYSTAGE} --description "Deployment by creation script for function ${functionName}${method}" > ${DEBUGFILE} diff --git a/Tooling/aws_method_request_passthrough.json b/Tooling/aws_method_request_passthrough.json deleted file mode 100644 index efea7ce..0000000 --- a/Tooling/aws_method_request_passthrough.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "body": $input.json('$'), - "context" : { - "sub" : "$context.authorizer.claims.sub", - "email" : "$context.authorizer.claims.email" - } -} \ No newline at end of file diff --git a/Tooling/body_and_auth_mapping.json b/Tooling/body_and_auth_mapping.json new file mode 100644 index 0000000..600bc4b --- /dev/null +++ b/Tooling/body_and_auth_mapping.json @@ -0,0 +1,3 @@ +{ + "application/json": "{\"body\": \"$input.json('$')\",\"context\" : {\"sub\" : \"$context.authorizer.claims.sub\",\"email\" : \"$context.authorizer.claims.email\"}}" +} \ No newline at end of file From 7fa74a7f9140a241e25d20ff9298af7861c3d11c Mon Sep 17 00:00:00 2001 From: Aaron Sun Date: Mon, 21 Sep 2020 14:51:18 -0700 Subject: [PATCH 06/11] Removed unncessary ListifyFrontend folder --- ListifyFrontend/.idea/modules.xml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 ListifyFrontend/.idea/modules.xml diff --git a/ListifyFrontend/.idea/modules.xml b/ListifyFrontend/.idea/modules.xml deleted file mode 100644 index 28d6d3e..0000000 --- a/ListifyFrontend/.idea/modules.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file From bbe0daff437c1e5033f2f4e3fa9b890ea21ab2a4 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 26 Sep 2020 11:15:06 -0400 Subject: [PATCH 07/11] Allow multiple method creation A resource should be able to accept multiple methods --- .../java/{ListAdd.java => InputUtils.java} | 19 ++-------------- Lambdas/Lists/src/main/java/ListsPOST.java | 22 +++++++++++++++++++ Tooling/EndpointSetup.sh | 12 ++++++---- 3 files changed, 32 insertions(+), 21 deletions(-) rename Lambdas/Lists/src/main/java/{ListAdd.java => InputUtils.java} (50%) create mode 100644 Lambdas/Lists/src/main/java/ListsPOST.java diff --git a/Lambdas/Lists/src/main/java/ListAdd.java b/Lambdas/Lists/src/main/java/InputUtils.java similarity index 50% rename from Lambdas/Lists/src/main/java/ListAdd.java rename to Lambdas/Lists/src/main/java/InputUtils.java index d5a698b..0457585 100644 --- a/Lambdas/Lists/src/main/java/ListAdd.java +++ b/Lambdas/Lists/src/main/java/InputUtils.java @@ -1,14 +1,7 @@ -import java.io.IOException; -import java.sql.SQLException; import java.util.Map; -import com.amazonaws.services.lambda.runtime.Context; -import com.amazonaws.services.lambda.runtime.RequestHandler; - -public class ListAdd implements RequestHandler, String>{ - - - public String handleRequest(Map inputMap, Context unfilled) { +public class InputUtils { + public static String getCognitoIDFromBody(Map inputMap) { System.out.println(inputMap.keySet()); System.out.println(inputMap.entrySet()); Map contextMap; @@ -19,13 +12,5 @@ public class ListAdd implements RequestHandler, String>{ } System.out.println(inputMap.get("context")); System.out.println(contextMap.get("sub")); - try { - System.out.println(new DBConnector()); - } catch (IOException e) { - e.printStackTrace(); - } catch (SQLException e) { - e.printStackTrace(); - } - return null; } } diff --git a/Lambdas/Lists/src/main/java/ListsPOST.java b/Lambdas/Lists/src/main/java/ListsPOST.java new file mode 100644 index 0000000..a4588a0 --- /dev/null +++ b/Lambdas/Lists/src/main/java/ListsPOST.java @@ -0,0 +1,22 @@ +import java.io.IOException; +import java.sql.SQLException; +import java.util.Map; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +public class ListsPOST implements RequestHandler, String>{ + + + public String handleRequest(Map inputMap, Context unfilled) { + String cognitoID = InputUtils.getCognitoIDFromBody(inputMap); + try { + System.out.println(new DBConnector()); + } catch (IOException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/Tooling/EndpointSetup.sh b/Tooling/EndpointSetup.sh index 81c2d08..6f2bf00 100644 --- a/Tooling/EndpointSetup.sh +++ b/Tooling/EndpointSetup.sh @@ -28,7 +28,7 @@ zipPath=${functionPath}.zip zip ${zipPath} ${jarPath} -RAWLAMBDA=$(aws lambda create-function --function-name ${functionName}${method} --zip-file fileb://${zipPath} --runtime ${LANGUAGE} --role ${LAMBDAROLE} --handler ${functionName}.lambda_handler) +RAWLAMBDA=$(aws lambda create-function --function-name ${functionName}${method} --zip-file fileb://${zipPath} --runtime ${LANGUAGE} --role ${LAMBDAROLE} --handler ${functionName}${method}.lambda_handler 2>${DEBUGFILE}) if [[ $? -ne 0 ]]; then echo "Unable to create Lamba" >&2 @@ -39,11 +39,15 @@ LAMBDAARN=$(echo $RAWLAMBDA | head -n 3 | tail -n 1 | cut -d \" -f 8) echo ${LAMBDAARN} > ${DEBUGFILE} -RAWRESOURCEID=$(aws apigateway create-resource --rest-api-id ${APIID} --parent-id ${ROOTRESOURCEID} --path-part ${functionName}) +RAWRESOURCEID=$(aws apigateway create-resource --rest-api-id ${APIID} --parent-id ${ROOTRESOURCEID} --path-part ${functionName} 2>${DEBUGFILE}) if [[ $? -ne 0 ]]; then - echo "Unable to create Resource. This needs to be handled at some future point" >&2 - exit 1 + echo "Unable to create resource." > ${DEBUGFILE} + RAWRESOURCEID=$(aws apigateway get-resources --rest-api-id datoh7woc9 --query "items[?pathPart==\`${functionName}\`].{id:id}" | head -n 3 | tail -n 1) + if [[ $RAWRESOURCEID == "[]" ]]; then + echo "Unable to create or find API Gateway resource." >&2 + exit 1 + fi fi RESOURCEID=$(echo ${RAWRESOURCEID} | head -n 2 | tail -n 1 | cut -d \" -f 4) From de0bd51eaf61f751035df69a1e2608cd2651bb21 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 26 Sep 2020 16:53:44 -0400 Subject: [PATCH 08/11] Basic ListAdd Lambda Create a basic list adding Lambda. NOTE: This does not include the following which are still needed: 1) Permanent DB Setup 2) Better RDS access control with security groups 3) Proper input parameters for the List add Lambda --- .gitignore | 2 ++ Lambdas/Lists/pom.xml | 5 ++++ Lambdas/Lists/src/main/java/DBConnector.java | 27 ++++++++++++++++--- Lambdas/Lists/src/main/java/InputUtils.java | 14 +++++++++- Lambdas/Lists/src/main/java/ListAdder.java | 23 ++++++++++++++++ Lambdas/Lists/src/main/java/ListsPOST.java | 14 +++++++--- .../Lists/target/classes/dbProperties.json | 5 ---- Tooling/EndpointSetup.sh | 26 ++++-------------- Tooling/LambdaUpdate.sh | 17 ++++++++++++ Tooling/VarSetup.sh | 26 ++++++++++++++++++ 10 files changed, 125 insertions(+), 34 deletions(-) delete mode 100644 Lambdas/Lists/target/classes/dbProperties.json create mode 100644 Tooling/LambdaUpdate.sh create mode 100644 Tooling/VarSetup.sh diff --git a/.gitignore b/.gitignore index 2fc6ec6..33561d7 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,5 @@ lint/outputs/ lint/tmp/ # lint/reports/ Lambdas/Lists/src/main/resources/dbProperties.json +Lambdas/Lists/target/classes/dbProperties.json +Lambdas/Lists/target/classes/META-INF/Lists.kotlin_module diff --git a/Lambdas/Lists/pom.xml b/Lambdas/Lists/pom.xml index 9442b49..8d77579 100644 --- a/Lambdas/Lists/pom.xml +++ b/Lambdas/Lists/pom.xml @@ -34,6 +34,11 @@ maven-compiler-plugin 3.8.1 + + org.mariadb.jdbc + mariadb-java-client + 2.7.0 + 1.11 diff --git a/Lambdas/Lists/src/main/java/DBConnector.java b/Lambdas/Lists/src/main/java/DBConnector.java index c4f85b9..074f4de 100644 --- a/Lambdas/Lists/src/main/java/DBConnector.java +++ b/Lambdas/Lists/src/main/java/DBConnector.java @@ -12,14 +12,28 @@ public class DBConnector { Connection connection; - DBConnector() throws IOException, SQLException { + DBConnector() throws IOException, SQLException, ClassNotFoundException { this(loadProperties("dbProperties.json")); } - DBConnector(Properties dbProperties) throws SQLException { + DBConnector(Properties dbProperties) throws SQLException, ClassNotFoundException { + Class.forName("org.mariadb.jdbc.Driver"); System.out.println(dbProperties); - connection = DriverManager.getConnection(dbProperties.get("url").toString(), dbProperties); + System.out.println(DBConnector.buildURL(dbProperties)); + connection = DriverManager.getConnection(dbProperties.get("url").toString(), dbProperties.get("user").toString(), dbProperties.get("password").toString()); + System.out.println(connection); + } + public void close() { + try { + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public Connection getConnection() { + return connection; } public static Properties loadProperties(String path) throws IOException { @@ -29,4 +43,11 @@ public class DBConnector { propertiesJSON.keys().forEachRemaining(key -> toReturn.setProperty(key, propertiesJSON.get(key).toString())); return toReturn; } + + public static String buildURL(Properties dbProperties) { + String dbURL = dbProperties.get("url").toString(); + dbURL += "?user=" + dbProperties.get("user").toString(); + dbURL += "&password=" + dbProperties.get("password").toString(); + return dbURL; + } } diff --git a/Lambdas/Lists/src/main/java/InputUtils.java b/Lambdas/Lists/src/main/java/InputUtils.java index 0457585..46a0694 100644 --- a/Lambdas/Lists/src/main/java/InputUtils.java +++ b/Lambdas/Lists/src/main/java/InputUtils.java @@ -8,9 +8,21 @@ public class InputUtils { if ((inputMap.get("context") != null) && (inputMap.get("context") instanceof Map)) { contextMap = ((Map) inputMap.get("context")); } else { - throw new IllegalArgumentException("The key \"Context\" must exist and be a map"); + throw new IllegalArgumentException("The key \"context\" must exist and be a map"); } System.out.println(inputMap.get("context")); System.out.println(contextMap.get("sub")); + return contextMap.get("sub").toString(); + } + + public static Map getBody(Map inputMap) { + return getMap(inputMap, "body"); + } + + public static Map getMap(Map parentMap, String childKey) { + if ((parentMap.get(childKey) != null) && (parentMap.get(childKey) instanceof Map)) { + return ((Map) parentMap.get(childKey)); + } + throw new IllegalArgumentException("The key \"" + childKey + "\" must exist and be a map"); } } diff --git a/Lambdas/Lists/src/main/java/ListAdder.java b/Lambdas/Lists/src/main/java/ListAdder.java index 413b7db..54745c5 100644 --- a/Lambdas/Lists/src/main/java/ListAdder.java +++ b/Lambdas/Lists/src/main/java/ListAdder.java @@ -1,4 +1,27 @@ +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Map; + public class ListAdder { + private DBConnector connector; + private String cognitoID; + private final String LIST_CREATE = "INSERT INTO Lists (Name, Owner) VALUES (?, ?)"; + + ListAdder(DBConnector connector, String cognitoID) { + this.connector = connector; + this.cognitoID = cognitoID; + } + + public void add(Map bodyMap) throws SQLException { + Connection connection = connector.getConnection(); + PreparedStatement statement = connection.prepareStatement(LIST_CREATE); + statement.setString(1, bodyMap.get("Name").toString()); + statement.setString(2, cognitoID); + System.out.println(statement); + statement.executeUpdate(); + connection.commit(); + } } diff --git a/Lambdas/Lists/src/main/java/ListsPOST.java b/Lambdas/Lists/src/main/java/ListsPOST.java index a4588a0..4068a4f 100644 --- a/Lambdas/Lists/src/main/java/ListsPOST.java +++ b/Lambdas/Lists/src/main/java/ListsPOST.java @@ -11,11 +11,17 @@ public class ListsPOST implements RequestHandler, String>{ public String handleRequest(Map inputMap, Context unfilled) { String cognitoID = InputUtils.getCognitoIDFromBody(inputMap); try { - System.out.println(new DBConnector()); - } catch (IOException e) { - e.printStackTrace(); - } catch (SQLException e) { + DBConnector connector = new DBConnector(); + try { + new ListAdder(connector, cognitoID).add(InputUtils.getBody(inputMap)); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + connector.close(); + } + } catch (IOException|SQLException|ClassNotFoundException e) { e.printStackTrace(); + throw new RuntimeException(e.getMessage()); } return null; } diff --git a/Lambdas/Lists/target/classes/dbProperties.json b/Lambdas/Lists/target/classes/dbProperties.json deleted file mode 100644 index ba1352b..0000000 --- a/Lambdas/Lists/target/classes/dbProperties.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "url": "http://aws.com/something", - "user": "aUser", - "password": "aPassword" -} \ No newline at end of file diff --git a/Tooling/EndpointSetup.sh b/Tooling/EndpointSetup.sh index 6f2bf00..a7ef691 100644 --- a/Tooling/EndpointSetup.sh +++ b/Tooling/EndpointSetup.sh @@ -2,33 +2,17 @@ #Base script from: https://github.com/NMerz/DoctorsNote/blob/master/AWS%20Setup/Lambda-GatewayInitialization.sh #NOTE: This has been tested and works; however, the apigateway does not properly show as a trigger in AWS's web UI -#NOTE2: This assumes that the root Gateway and Lambda role have been set up previously (one-time setup) and their values are stored in the constants below +#NOTE2: This assumes that the root Gateway and Lambda role have been set up previously (one-time setup) and their values are set in VarSetup.sh -#constants -APIID=datoh7woc9 #rest-api-id is tied to the apigateway while resource-id seems tied to the specific url extension -ROOTRESOURCEID=6xrzhzidxh #gateway root should have a consistent resource id which will serve as parent for many apis -LAMBDAROLE=arn:aws:iam::569815541706:role/LambdaBasic -LANGUAGE=java11 -DEPLOYSTAGE=Development +echo "Creating a Gateway/Lambda pair." -DEBUGFILE=/dev/null +REL_SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") -echo -n "Please enter function/endpoint name: " -read functionName -echo -n "Please enter method(GET, POST, etc.): " -read method +source ${REL_SCRIPT_DIR}/VarSetup.sh -jarPath=$(find .. -name "${functionName}.jar") -if [[ "$jarPath" == "" ]]; then - echo "Unable to find file ${functionName}.jar" >&2 - exit 1 -fi -functionPath=${jarPath%/${functionName}.jar} -zipPath=${functionPath}.zip -zip ${zipPath} ${jarPath} +RAWLAMBDA=$(aws lambda create-function --function-name ${functionName}${method} --zip-file fileb://${zipPath} --runtime ${LANGUAGE} --role ${LAMBDAROLE} --handler ${functionName}${method} 2>${DEBUGFILE}) -RAWLAMBDA=$(aws lambda create-function --function-name ${functionName}${method} --zip-file fileb://${zipPath} --runtime ${LANGUAGE} --role ${LAMBDAROLE} --handler ${functionName}${method}.lambda_handler 2>${DEBUGFILE}) if [[ $? -ne 0 ]]; then echo "Unable to create Lamba" >&2 diff --git a/Tooling/LambdaUpdate.sh b/Tooling/LambdaUpdate.sh new file mode 100644 index 0000000..0f49b9b --- /dev/null +++ b/Tooling/LambdaUpdate.sh @@ -0,0 +1,17 @@ +#!/bin/bash +echo "Updating a Lambda." + +REL_SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") + +source ${REL_SCRIPT_DIR}/VarSetup.sh + + +aws lambda update-function-code --function-name ${functionName}${method} --zip-file fileb://${jarPath} 1>${DEBUGFILE} 2>${DEBUGFILE} + +if [[ $? -ne 0 ]]; then + echo "Unable to update Lamba" >&2 + exit 1 +fi + +echo "Update successful." +exit 0 diff --git a/Tooling/VarSetup.sh b/Tooling/VarSetup.sh new file mode 100644 index 0000000..4ff07fb --- /dev/null +++ b/Tooling/VarSetup.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Meant to be source'd from other scripts that need these vars. + +#constants +APIID=datoh7woc9 #rest-api-id is tied to the apigateway while resource-id seems tied to the specific url extension +ROOTRESOURCEID=6xrzhzidxh #gateway root should have a consistent resource id which will serve as parent for many apis +LAMBDAROLE=arn:aws:iam::569815541706:role/LambdaBasic +LANGUAGE=java11 +DEPLOYSTAGE=Development + +DEBUGFILE=/dev/null + +REL_SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") + +echo -n "Please enter base function name: " +read functionName +echo -n "Please enter method(GET, POST, etc.): " +read method + +jarPath=$(find ${REL_SCRIPT_DIR}/.. -name "${functionName}.jar") +if [[ "$jarPath" == "" ]]; then + echo "Unable to find file ${functionName}.jar" >&2 + exit 1 +fi +functionPath=${jarPath%/${functionName}.jar} \ No newline at end of file From 2c9334ee9e1810e40aeabdf95c2b76ddd5bb73bf Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 27 Sep 2020 11:54:26 -0400 Subject: [PATCH 09/11] Client API connection infrastructure Create the infrastructure for the client to connect to API gateway in a generic manner. Tested with the ListPOST lambda. --- .gitignore | 1 + Lambdas/Lists/src/main/java/ListAdder.java | 2 +- .../java/{ListsPOST.java => ListPOST.java} | 2 +- Listify/.idea/gradle.xml | 1 + Listify/.idea/misc.xml | 2 +- Listify/app/build.gradle | 15 +- .../java/com/example/listify/AuthManager.java | 27 ++- .../main/java/com/example/listify/List.java | 8 + .../com/example/listify/MainActivity.java | 46 +++-- .../java/com/example/listify/Requestor.java | 66 +++++++ .../example/listify/ui/home/HomeFragment.java | 1 + Listify/build.gradle | 1 + Listify/gradle.properties | 2 +- Listify/gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 3 +- Listify/gradlew | 53 ++++-- Listify/gradlew.bat | 173 +++++++++--------- Tooling/EndpointSetup.sh | 4 +- Tooling/body_and_auth_mapping.json | 4 +- 19 files changed, 275 insertions(+), 136 deletions(-) rename Lambdas/Lists/src/main/java/{ListsPOST.java => ListPOST.java} (91%) create mode 100644 Listify/app/src/main/java/com/example/listify/List.java create mode 100644 Listify/app/src/main/java/com/example/listify/Requestor.java mode change 100644 => 100755 Listify/gradlew diff --git a/.gitignore b/.gitignore index 33561d7..837a882 100644 --- a/.gitignore +++ b/.gitignore @@ -87,3 +87,4 @@ lint/tmp/ Lambdas/Lists/src/main/resources/dbProperties.json Lambdas/Lists/target/classes/dbProperties.json Lambdas/Lists/target/classes/META-INF/Lists.kotlin_module +Listify/app/src/main/res/raw/auths.json diff --git a/Lambdas/Lists/src/main/java/ListAdder.java b/Lambdas/Lists/src/main/java/ListAdder.java index 54745c5..e1598b7 100644 --- a/Lambdas/Lists/src/main/java/ListAdder.java +++ b/Lambdas/Lists/src/main/java/ListAdder.java @@ -18,7 +18,7 @@ public class ListAdder { public void add(Map bodyMap) throws SQLException { Connection connection = connector.getConnection(); PreparedStatement statement = connection.prepareStatement(LIST_CREATE); - statement.setString(1, bodyMap.get("Name").toString()); + statement.setString(1, bodyMap.get("name").toString());//Needs safe checking statement.setString(2, cognitoID); System.out.println(statement); statement.executeUpdate(); diff --git a/Lambdas/Lists/src/main/java/ListsPOST.java b/Lambdas/Lists/src/main/java/ListPOST.java similarity index 91% rename from Lambdas/Lists/src/main/java/ListsPOST.java rename to Lambdas/Lists/src/main/java/ListPOST.java index 4068a4f..c2fc63c 100644 --- a/Lambdas/Lists/src/main/java/ListsPOST.java +++ b/Lambdas/Lists/src/main/java/ListPOST.java @@ -5,7 +5,7 @@ import java.util.Map; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; -public class ListsPOST implements RequestHandler, String>{ +public class ListPOST implements RequestHandler, String>{ public String handleRequest(Map inputMap, Context unfilled) { diff --git a/Listify/.idea/gradle.xml b/Listify/.idea/gradle.xml index 5cd135a..674414f 100644 --- a/Listify/.idea/gradle.xml +++ b/Listify/.idea/gradle.xml @@ -4,6 +4,7 @@