API Gateway сгенерировал SDK для iOS (Objective-C) с пулом пользователей Cognito для авторизованных пользователей

Я развернул API с помощью AWS API Gateway и пытаюсь получить к нему доступ через устройство iOS. Некоторые конечные точки поддерживают неавторизованных пользователей, и у меня нет проблем с доступом к ним, но другие нет, и я не могу их запросить. Я использую новую функцию Cognito User Pool для аутентификации, которая отлично работает при использовании веб-приложения (или почтальона).

Во-первых, даже несмотря на то, что некоторые конечные точки защищены (как на следующем изображении консоли), когда я развертываю API и генерирую SDK для iOS (Objective-C), я могу прочитать в файле README: «Все конечные точки работают. не требует авторизации ".

введите здесь описание изображения

Затем, когда я запускаю следующий код аутентификации из документации AWS, все работает нормально:

AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionEUWest1 credentialsProvider:nil];
AWSCognitoIdentityUserPoolConfiguration *userPoolConfiguration = [[AWSCognitoIdentityUserPoolConfiguration alloc] initWithClientId:ClientId  clientSecret:nil poolId:UserPoolId];
[AWSCognitoIdentityUserPool registerCognitoIdentityUserPoolWithConfiguration:serviceConfiguration userPoolConfiguration:userPoolConfiguration forKey:@"UserPool"];
AWSCognitoIdentityUserPool *pool = [AWSCognitoIdentityUserPool CognitoIdentityUserPoolForKey:@"UserPool"];

AWSCognitoIdentityUser *user = [pool getUser];
[[user getSession:username password:password validationData:nil] continueWithBlock:^id(AWSTask<AWSCognitoIdentityUserSession *> *task) {
    if (task.error) {
        NSLog(@"Could not get user session. Error: %@", task.error);
    } else if (task.exception) {
        NSLog(@"Could not get user session. Exception: %@", task.exception);
    } else {
        NSLog(@"Successfully retrieved user session data");
        AWSCognitoIdentityUserSession *session = (AWSCognitoIdentityUserSession *) task.result;

        NSMutableString *poolId = [[NSMutableString alloc] initWithString:@"cognito-idp.eu-west-1.amazonaws.com/"];
        [poolId appendString:UserPoolId];
        NSString *tokenStr = [session.idToken tokenString];
        NSDictionary *tokens = [[NSDictionary alloc] initWithObjectsAndKeys:tokenStr, poolId, nil];



        CognitoPoolIdentityProvider *idProvider = [[CognitoPoolIdentityProvider alloc] init];
        [idProvider addTokens:tokens];

        AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionEUWest1 identityPoolId:IdentityPoolId identityProviderManager:idProvider];

        [credentialsProvider clearKeychain];
        [credentialsProvider clearCredentials];

        AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionEUWest1
                                                                                                          credentialsProvider:credentialsProvider];

        [[credentialsProvider getIdentityId] continueWithBlock:^id _Nullable(AWSTask<NSString *> * _Nonnull task) {
            if (task.error) {
                NSLog(@"Could not get identity id: %@", task.error);
            } else if (task.exception) {
                NSLog(@"Could not get identity id: %@", task.exception);
            } else {
                NSLog(@"Identity id: %@", task.result);
            }

            return nil;
         }];
    }

    return nil;
}];

Я реализовал CognitoPoolIdentityProvider, как указано в этом сообщении .

@interface CognitoPoolIdentityProvider ()
@property (strong, nonatomic) NSDictionary *tokens;
@end

@implementation CognitoPoolIdentityProvider

    - (AWSTask<NSDictionary *> *)logins {
        return [AWSTask taskWithResult:self.tokens];
    }

    - (void)addTokens:(NSDictionary *)tokens {
        self.tokens = tokens;
    }

@end

Мне удалось получить правильный токен (проверено с помощью почтальона) и идентификатор пользователя:

2016-12-27 12: 43: 35.760 AskHub [26625: 10037234] AWSiOSSDK v2.4.11 [Debug] Строка AWSURLResponseSerialization.m: 63 | - [AWSJSONResponseSerializer responseObjectForResponse: originalRequest: currentRequest: data: error:] | Тело ответа: {"IdentityId": "eu-west-1: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"} 2016-12-27 12: 43: 35.766 AskHub [26625: 10037234] Идентификационный идентификатор: eu-west-1 : XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

Однако, когда я запускаю следующий код для попадания в защищенную конечную точку, CloudFront считает, что я не аутентифицирован.

APIHealthClient *apiClient = [APIHealthClient defaultClient];
APIAskHubRequest *initReq = [[APIAskHubRequest alloc] init];
initReq.message = @"FIN";

NSLog(@"Sending initial request");
[[apiClient webhooksAskhubPost:initReq] continueWithBlock:^id(AWSTask *task) {
    if (task.error) {
        NSLog(@"Could not send initial request: %@", task.error);
    } else if (task.exception) {
        NSLog(@"Could not send initial request: %@", task.exception);
    } else {
        NSLog(@"Successfully sent initial request");
    }

    return nil;
}];

Ответ:

2016-12-27 12: 56: 25.247 AskHub [26784: 10046562] Не удалось отправить первоначальный запрос: Error Domain = com.amazonaws.AWSAPIGatewayErrorDomain Code = 1 "(null)" UserInfo = {HTTPBody = {message = Unauthorized; }, HTTPHeaderFields = {type = immutable dict, count = 9, entries => 3: Via = {contents = "XX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.cloudfront.net (CloudFront)"} 4: x-amzn-ErrorType = {contents = "UnauthorizedException } 5: Content-Type = {contents = "application / json"} 6: Content-Length = {contents = "27"} 7: Connection = {contents = "keep-alive"} 8: x-amzn-RequestId = {contents = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"} 9: Date = {contents = "Вт, 27 декабря 2016 г., 11:56:25 GMT"} 10: X-Cache = {contents = "Ошибка облачного интерфейса" } 11: X-Amz-Cf-Id = {contents = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}}}

Я что-то упустил? Поддерживает ли автоматически созданный SDK аутентификацию пула пользователей?


person Hatim Khouzaimi    schedule 27.12.2016    source источник
comment
У меня точно такая же проблема, как и у вас ... У меня есть api, авторизация которого осуществляется через мой пул пользователей когнитивного доступа. Когда я вызываю этот api через почтальона с переданным заголовком авторизации с действительным токеном идентификатора от пользователя в моем пользовательском пуле, он работает. Однако, когда я пытаюсь вызвать тот же api через ios с сгенерированным api ios sdk, я получаю ту же ошибку. Я предполагаю, что еще одна вещь в ios еще не настроена? Я собираюсь продолжать пыхтеть и писать здесь, если найду это.   -  person Jason Chitla    schedule 29.12.2016


Ответы (2)


Основываясь на коде, который я вижу, вы очищаете учетные данные, но никогда не получаете учетные данные. При быстром просмотре кажется, что вы правильно настраиваете конфигурацию службы и аутентификацию, но никогда не вызываете учетные данные.

Если бы это было так, даже если бы ваше приложение аутентифицировалось, провайдер учетных данных никогда бы не получил словарь логинов.

(Вы можете проверить это в Консоли AWS, если вы посмотрите на identityId, который вы пытаетесь использовать для доступа к ресурсу, вы можете посмотреть счетчик «входов в систему». Если он равен 0, вы не вошли в систему.)

Для аутентификации вам необходимо, чтобы провайдер учетных данных вызывал ваш метод логинов identityProviderManager.

Этот вызов происходит, когда вы выполняете getCredentialsForIdentity, что является «учетными данными» в SDK.

Обычно последовательность - это GetID, за которым следует GetCredentialsForId. В IOS SDK GetId происходит с «getSession» (так что вы должны это иметь), а GetCredentials - с «учетными данными».

(Обратите внимание, что существуют разные SDK с разными именами в каждом (например, Mobile Hub против IOS SDK), но все, что имеет значение, это то, что ваш провайдер учетных данных получает словарь входа в систему. При подробном ведении журнала вы должны фактически видеть журнал «логинов», который докажет вам, что поставщику учетных данных предоставляется словарь логинов).

person Bruce0    schedule 27.12.2016
comment
Спасибо за уточнение. Я попытался вызвать учетные данные, и, похоже, это сработало, поскольку я могу регистрировать AccessKey, SecretKey и SessionKey. Однако, когда я потом устанавливаю defaultServiceConfiguration (используя новый credentialsProvider), а затем вызываю API, я все равно получаю UnauthorizedException ... - person Hatim Khouzaimi; 27.12.2016
comment
Есть ли у вас в файле журнала словарь логинов? Вот так: X-Amz-Target = AWSCognitoIdentityService.GetCredentialsForIdentity; } 27.12.2016 17: 09: 30.736 KeyCode [3004: 122424] AWSiOSSDK v2.4.14 [Debug] AWSURLSessionManager.m строка: 555 | - [AWSURLSessionManager printHTTPHeadersAndBodyForRequest:] | Тело запроса: {Logins: {cognito-idp.us-east-1.amazonaws.com \ / us-east-1_xxxxxxxxx ”:” eyJraWQixxxxxxxxxx long long-code tokenxxxxxj3f2QzWX5o8AVdtDPA}, IdentityId: us-east-1: ”} - person Bruce0; 28.12.2016
comment
получить логины больше 0 в консоли aws для рассматриваемого identityId? - person Bruce0; 28.12.2016
comment
Да, у меня есть словарь логинов, с той лишь разницей, что у меня AWSURLSessionManager.m строка: 543 вместо строки: 555. Думаю, мы используем разные версии SDK, не могли бы вы сообщить мне, какой из них вы используете, если он работает. Логины больше 0, это было 1, и, конечно же, я создал нового пользователя и выполнил свой код с новым логином / паролем, и теперь у меня есть 2 идентификатора в консоли. - person Hatim Khouzaimi; 28.12.2016
comment
Итак: вы вошли в систему и прошли аутентификацию. Я прав, что мы можем отклонить политики IAM, потому что то, что не работает в приложении IOS, работает в веб-приложении? Если это так, убедитесь, что: 1) Роль, в которой произошел сбой, - это Роль, прошедшая проверку подлинности (см. Это в журналах). 2) Идентификатор клиента приложения из пользовательского пула для вашего приложения совпадает с идентификатором, используемым в поставщиках аутентификации в федеративной конфигурации (и если вы создаете поставщик удостоверений, который обычно не требуется, в IAM, убедитесь, что аудитория соответствует идентификатору клиента приложения. ). - person Bruce0; 28.12.2016
comment
Также - вы работаете с единым федеративным пулом? Это изменилось? Политика GetId СОДЕРЖИТ идентификаторы пула удостоверений (хотя, похоже, это работает), а политики доверия содержат идентификаторы доверенного идентификатора федеративного пула. - person Bruce0; 28.12.2016
comment
Наконец, уверены ли вы, что служба, которую вы пытаетесь использовать, была зарегистрирована в конфигурации службы, которую вы используете? На самом деле ... сначала проверьте это. - person Bruce0; 28.12.2016
comment
Разве этой строки недостаточно для регистрации службы: [AWSCognitoIdentityUserPool registerCognitoIdentityUserPoolWithConfiguration: serviceConfiguration userPoolConfiguration: userPoolConfiguration forKey: @UserPool] ;. Также я обнаружил интересный факт: при подключении к веб-приложению или почтальону количество идентификаторов в консоли не увеличивается. Поскольку все, что я делаю, это добавляю jwtToken в поле Authorizer в заголовке HTTP, я полагаю, это не запускает процесс AssumeRole, в отличие от того, что происходит в моем приложении для iOS ... - person Hatim Khouzaimi; 29.12.2016
comment
Я попытался добавить несколько разрешений, например execute-api: Invoke, для связанной аутентифицированной роли IAM, но проблема сохраняется. - person Hatim Khouzaimi; 29.12.2016
comment
Я не знаю, что такое APIHealthClient и какие службы он пытается использовать, но обычно каждую из служб необходимо зарегистрировать при инициализации. Выполняемая вами регистрация регистрирует пулы пользователей, чтобы вы могли войти в систему, и я немного не в своем уме (я не знаю облачного интерфейса), но разве вам не нужно регистрировать какой-то сервис AWS, который вы пытаетесь использовать? - person Bruce0; 29.12.2016
comment
APIHealthClient является частью SDK, автоматически генерируемого APIGateway (мой API называется Health с API в качестве префикса). Я не совсем понимаю, что мне нужно регистрировать, но вопрос, который вы подняли по поводу федеративных удостоверений, весьма интересен. Мне кажется, что достаточно добавить правильный токен в поле авторизации в моем HTTP-запросе (который я делаю вручную и в своем веб-приложении), и мне не нужно брать на себя какую-либо роль, используя когнито (что объясняет отсутствие увеличение счетчика идентификаторов в Федеративном удостоверении) ... - person Hatim Khouzaimi; 29.12.2016
comment
Я подозреваю, что увеличение счетчика идентификаторов вызвано тем, что ваше приложение всегда очищает связку ключей. Вызов очистки учетных данных или другой вызов, который вы делаете, получит новый идентификатор identityId. Затем выполните аутентификацию, и вы вернетесь и получите тот же старый (очищенный) идентификатор, и в этом процессе вы откажетесь от другого идентификатора (и никогда не сможете получить к нему доступ снова, я считаю, что он будет помечен как DISABLE (консоль имеет опечатку. .. без рекламы, но значит ОТКЛЮЧЕН) в консоли. - person Bruce0; 30.12.2016
comment
Наконец-то мне удалось правильно использовать API, сделав то же самое, что и в веб-приложении. Я добавил параметр заголовка авторизации в спецификацию API (сгенерированный SDK адаптируется соответствующим образом), а затем заполняю его непосредственно токеном. Документация, представленная в этой части, ужасно вводит в заблуждение с моей точки зрения, хотя я, возможно, что-то упустил. В любом случае, большое спасибо Брюсу за вашу помощь и с Новым годом! - person Hatim Khouzaimi; 02.01.2017
comment
Все, что вы сделали, это добавили заголовок авторизации в запрос метода API и восстановили ios sdk? У меня есть этот заголовок, но он все равно не сработает. Вы выбрали кеширование рядом с этим заголовком? Источник токена идентификации для вашего авторизатора когнитивного анализа: method.request.header.Authorization? - person Jason Chitla; 03.01.2017

Я понял, что здесь есть путаница между двумя типами режимов аутентификации: с использованием поставщика учетных данных или просто добавлением токена JWT в параметр заголовка «Авторизация» (или имя вашего настраиваемого параметра, если вы указали его при создании авторизатора).

Первый метод у меня не сработал, хотя он единственный, который я нашел в документации, когда дело доходит до использования iOS SDK. Второй метод работает довольно хорошо, но чтобы иметь возможность использовать его без взлома SDK, не забудьте добавить заголовок «Авторизация», когда вы указываете свой API в API Gateway.

person Hatim Khouzaimi    schedule 02.01.2017