Search code examples
swiftssl-certificatealamofirerxalamofire

Got error Alamofire.AFError.ServerTrustFailureReason.noRequiredEvaluator when using DisabledTrustEvaluator


I've got a class AuthenticationApiClient that has this integration test:

func testCheckPhoneNumber_WithExistingPhoneNumber_ShouldReturnRegisteredStatus() throws {
    let sessionFactory: () -> Session = {
        let serverTrustManager = ServerTrustManager(evaluators: ["xxx.xxx.xxx.xxx:8443" : DisabledTrustEvaluator()])
        let session = Session(serverTrustManager: serverTrustManager)
        return session
    }
    let hostFactory: () -> String = {
        return "https://xxx.xxx.xxx.xxx:8443/staging/"
    }
    let sut = AuthenticationApiClient(sessionFactory: sessionFactory, 
                                      hostFactory: hostFactory)
    let expectSuccess = expectation(description: "Should return phone number data from API")
    let params = PhoneRegistrationRequestModel(vendorId: "xxxxxxxxxx",
                                               phoneNumber: "xxxxxxxxxx",
                                               idFA: "xxxxxxxxxxx")
    sut.checkPhoneNumber(params)
        .subscribe(onNext: { responseModel in
            expectSuccess.fulfill()
            XCTAssertEqual(false, responseModel.rdl)
            XCTAssertEqual("00", responseModel.registrantStatus)
        }, onError: { error in
            XCTFail("Returned error: \(error)")
        })
        .disposed(by: disposeBag)
    wait(for: [expectSuccess], timeout: 5)
}

This is for staging environment where I don't need any SSL evaluation. That's why I used the DisabledTrustEvaluator But when I run this, I've got this error:

serverTrustEvaluationFailed(reason: Alamofire.AFError.ServerTrustFailureReason.noRequiredEvaluator(host: "xxx.xxx.xxx.xxx"))

But when I used Session.default, it throws this:

sessionTaskFailed(error: Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “xxx.xxx.xxx.xxx” which could put your confidential information at risk." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=(.....

The code for AuthenticationApiClient is like this:

protocol AuthenticationApiClient {
    func checkPhoneNumber(_ params: PhoneRegistrationRequestModel) -> Observable<PhoneRegistrationResponseModel>
}

final class AuthenticationApi: AuthenticationApiClient {
    private let session: Session
    private let host: String
    init(sessionFactory: @escaping () -> Session,
         hostFactory: @escaping () -> String) {
        session = sessionFactory()
        host = hostFactory()
    }
    func checkPhoneNumber(_ params: PhoneRegistrationParam) -> Observable<PhoneRegistrationResponseModel> {
        let endpoint = "getRegistrantIdByPhone"
        guard let url = URL(string: host+endpoint) else { return .empty() }
        let httpHeaders: HTTPHeaders = HTTPHeadersMapper.map(from: ApiHeaders.default)

        return session.rx
            .data(.post, url,
                  parameters: params.toStringDictionary(), 
                  encoding: JSONEncoding.default,
                  headers: httpHeaders)
            .map { PhoneRegistrationResponseModelMapper.map($0) }
    }
}

What did I do wrong here? Can anybody help me? Thanks.

PS: Forgot to say that I'm using Swift 5, Alamofire 5.5.0 and RxAlamofire 6.1.1


Solution

  • By default all ServerTrustManagers require every host they see to match at least one evaluator. If you don't want that behavior you can you disable it when you create the ServerTrustManager instance: ServerTrustManager(allHostsMustBeEvaluated: false, evaluators: ...).