Брелок Xamarin.iOS зависает при попытке запросить ключ, хранящий NSData - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть развернутое приложение, которое использует OpenID Connect для аутентификации.После проверки подлинности я сохраняю объект AuthState в цепочке для ключей iOS для безопасности и для возможности входа пользователя позже с помощью только Face / Touch ID (учитывая, что токен обновления в AuthState все еще действителен).Объект AuthState выглядит следующим образом:

namespace OpenId.AppAuth
{
    [Register ("OIDAuthState", true)]
    public class AuthState : NSObject, INSCoding, INativeObject, IDisposable, INSSecureCoding
    {
        [CompilerGenerated]
        private static readonly IntPtr class_ptr = Class.GetHandle ("OIDAuthState");

        [CompilerGenerated]
        private object __mt_ErrorDelegate_var;

        [CompilerGenerated]
        private object __mt_StateChangeDelegate_var;

        public override IntPtr ClassHandle {
            get;
        }

        [CompilerGenerated]
        public virtual NSError AuthorizationError {
            [Export ("authorizationError")]
            get;
        }

        [CompilerGenerated]
        public virtual IAuthStateErrorDelegate ErrorDelegate {
            [Export ("errorDelegate", ArgumentSemantic.Weak)]
            get;
            [Export ("setErrorDelegate:", ArgumentSemantic.Weak)]
            set;
        }

        [CompilerGenerated]
        public virtual bool IsAuthorized {
            [Export ("isAuthorized")]
            get;
        }

        [CompilerGenerated]
        public virtual AuthorizationResponse LastAuthorizationResponse {
            [Export ("lastAuthorizationResponse")]
            get;
        }

        [CompilerGenerated]
        public virtual RegistrationResponse LastRegistrationResponse {
            [Export ("lastRegistrationResponse")]
            get;
        }

        [CompilerGenerated]
        public virtual TokenResponse LastTokenResponse {
            [Export ("lastTokenResponse")]
            get;
        }

        [CompilerGenerated]
        public virtual string RefreshToken {
            [Export ("refreshToken")]
            get;
        }

        [CompilerGenerated]
        public virtual string Scope {
            [Export ("scope")]
            get;
        }

        [CompilerGenerated]
        public virtual IAuthStateChangeDelegate StateChangeDelegate {
            [Export ("stateChangeDelegate", ArgumentSemantic.Weak)]
            get;
            [Export ("setStateChangeDelegate:", ArgumentSemantic.Weak)]
            set;
        }

        public static IAuthorizationFlowSession PresentAuthorizationRequest (AuthorizationRequest authorizationRequest, UIViewController presentingViewController, AuthStateAuthorizationCallback callback);

        [CompilerGenerated]
        [DesignatedInitializer]
        [EditorBrowsable (EditorBrowsableState.Advanced)]
        [Export ("initWithCoder:")]
        public AuthState (NSCoder coder)
            : base (NSObjectFlag.Empty);

        [CompilerGenerated]
        [EditorBrowsable (EditorBrowsableState.Advanced)]
        protected AuthState (NSObjectFlag t)
            : base (t);

        [CompilerGenerated]
        [EditorBrowsable (EditorBrowsableState.Advanced)]
        protected internal AuthState (IntPtr handle)
            : base (handle);

        [Export ("initWithAuthorizationResponse:")]
        [CompilerGenerated]
        public AuthState (AuthorizationResponse authorizationResponse)
            : base (NSObjectFlag.Empty);

        [Export ("initWithAuthorizationResponse:tokenResponse:")]
        [CompilerGenerated]
        public AuthState (AuthorizationResponse authorizationResponse, TokenResponse tokenResponse)
            : base (NSObjectFlag.Empty);

        [Export ("initWithRegistrationResponse:")]
        [CompilerGenerated]
        public AuthState (RegistrationResponse registrationResponse)
            : base (NSObjectFlag.Empty);

        [Export ("initWithAuthorizationResponse:tokenResponse:registrationResponse:")]
        [DesignatedInitializer]
        [CompilerGenerated]
        public AuthState (AuthorizationResponse authorizationResponse, TokenResponse tokenResponse, RegistrationResponse registrationResponse)
            : base (NSObjectFlag.Empty);

        [Export ("encodeWithCoder:")]
        [CompilerGenerated]
        [Preserve (Conditional = true)]
        public virtual void EncodeTo (NSCoder encoder);

        [Export ("performActionWithFreshTokens:")]
        [CompilerGenerated]
        public unsafe virtual void PerformWithFreshTokens ([BlockProxy (typeof(ObjCRuntime.Trampolines.NIDAuthStateAction))] AuthStateAction action);

        [Export ("performActionWithFreshTokens:additionalRefreshParameters:")]
        [CompilerGenerated]
        public unsafe virtual void PerformWithFreshTokens ([BlockProxy (typeof(ObjCRuntime.Trampolines.NIDAuthStateAction))] AuthStateAction action, NSDictionary<NSString, NSString> additionalParameters);

        [Export ("authStateByPresentingAuthorizationRequest:UICoordinator:callback:")]
        [CompilerGenerated]
        public unsafe static IAuthorizationFlowSession PresentAuthorizationRequest (AuthorizationRequest authorizationRequest, IAuthorizationUICoordinator UICoordinator, [BlockProxy (typeof(ObjCRuntime.Trampolines.NIDAuthStateAuthorizationCallback))] AuthStateAuthorizationCallback callback);

        [Export ("setNeedsTokenRefresh")]
        [CompilerGenerated]
        public virtual void SetNeedsTokenRefresh ();

        [Export ("tokenRefreshRequest")]
        [CompilerGenerated]
        public virtual TokenRequest TokenRefreshRequest ();

        [Export ("tokenRefreshRequestWithAdditionalParameters:")]
        [CompilerGenerated]
        public virtual TokenRequest TokenRefreshRequest (NSDictionary<NSString, NSString> additionalParameters);

        [Export ("updateWithAuthorizationResponse:error:")]
        [CompilerGenerated]
        public virtual void Update (AuthorizationResponse authorizationResponse, NSError error);

        [Export ("updateWithTokenResponse:error:")]
        [CompilerGenerated]
        public virtual void Update (TokenResponse tokenResponse, NSError error);

        [Export ("updateWithAuthorizationError:")]
        [CompilerGenerated]
        public virtual void Update (NSError authorizationError);

        [Export ("updateWithRegistrationResponse:")]
        [CompilerGenerated]
        public virtual void UpdateWithRegistrationResponse (RegistrationResponse registrationResponse);

        [CompilerGenerated]
        protected override void Dispose (bool disposing);
    }
}

До обновления iOS 12.1 все работало отлично

ПРОБЛЕМА: только после установки обновления ios 12.1, толькопри работе в режиме выпуска (работает при отладке в режиме разработки при подключении к VS для отладчика Mac) запрос существующего ключа в цепочке для ключей, хранящей двоичное NSData представление этого AuthState объекта , зависает и в конечном итоге приложение завершается за отсутствие ответа более 10 секунд.

Кто-нибудь сталкивался с подобными проблемами?Было бы замечательно, если бы кто-нибудь мог пролить свет на то, что здесь происходит, или указать мне правильное направление.

Дополнительная информация:

Как получить NSData двоичное представление AppAuth object:

NSData authStateData = NSKeyedArchiver.ArchivedDataWithRootObject(authState);

Как сохранить это NSData в цепочке для ключей:

    var secAccess = new SecAccessControl(SecAccessible.WhenUnlockedThisDeviceOnly, SecAccessControlCreateFlags.UserPresence);
    var secRecord = new SecRecord(SecKind.GenericPassword)
    {
        Account = "keystring",
        Service = "ServiceNameString",
        Label = "keystring",
        ValueData = authStateData,
        AccessControl = secAccess
    };
    var result = SecKeyChain.Add(secRecord);

Как запросить существующие данные в keychain:

var searchRecord = new SecRecord(SecKind.GenericPassword)
{
    Service = ServiceName,
    Label = key,
};
var match = SecKeyChain.QueryAsRecord(searchRecord, out SecStatusCode resultCode);

В журнале устройства нет явных ошибок, я проверял.Произошло ли изменение в iOS 12.1, которое я пропустил, и это существенно влияет на это?

ОБНОВЛЕНИЕ: Я реорганизовал код для хранения только пароля ключа шифрования в цепочке для ключей вместо целого объекта AuthState ивместо этого сохраните сериализованный AuthState в зашифрованном виде в локальном файле.Все еще видя ту же проблему, в режиме отладки на устройстве все работает, пишет и читает из цепочки для ключей просто отлично, при запуске без отладчика, подключенного на том же устройстве, та же сборка, пишет хорошо, когда чтение зависает после успешной проверки TouchID / FaceID,есть ошибка в Xamarin.iOS SDK, которая не привела к каким-либо изменениям в последней iOS, которая вызывает это?

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Я исправил проблему, которая возникла у меня, похоже, это было какое-то состояние гонки, которое блокировало приложение, поскольку в главном потоке выполнялся вызов для сохранения в связку ключей.Обычно этот вызов очень быстрый, и в прошлом никогда не возникало проблем с блокировкой, но что-то в обновлении iOS 12.1 изменило это.В любом случае, я просто явно запустил код, сохраняя пароль шифрования в цепочке для ключей в фоновом потоке, и это устранило проблему:

Task.Run(() =>
{
    var keychain = new KeyChain();
    keychain.SetValueForKey("securedvalue", "securedvaluekey");
}).ConfigureAwait(false);
0 голосов
/ 29 ноября 2018

Вы должны включить разрешение на совместное использование цепочки для ключей.

в Entitlements.plist

enter image description here

И вот аналогичный случай вы можете сослаться.

...