docs: function login(opts, cb) {
      assert.object(opts, 'opts');
      assert.ok(opts.index || opts.indexName,
          'opts.index or opts.indexName is required');
      assert.optionalString(opts.username, 'opts.username');
      if (opts.username) {
          assert.string(opts.password,
              'opts.password required if username given');
      } else {
          assert.optionalString(opts.password, 'opts.password');
      }
      assert.optionalString(opts.scope, 'opts.scope');
      assert.optionalString(opts.userAgent, 'opts.userAgent');
      assert.optionalBool(opts.insecure, 'opts.insecure');
      assert.optionalObject(opts.pingRes, 'opts.pingRes');
      if (opts.pingRes && opts.pingRes.statusCode !== 200) {
          assert.object(opts.pingErr, 'opts.pingErr');
      } else {
          assert.optionalObject(opts.pingErr, 'opts.pingErr');
      }
      assert.optionalObject(opts.log, 'opts.log');
      assert.optionalString(opts.userAgent, 'opts.userAgent');
      assert.optionalObject(opts.agent, 'opts.agent');
      // assert.optional object or bool(opts.proxy, 'opts.proxy');
      assert.func(cb, 'cb');
  
      var index = opts.index || opts.indexName;
      if (typeof (index) === 'string') {
          try {
              index = common.parseIndex(index);
          } catch (indexNameErr) {
              cb(indexNameErr);
              return;
          }
      } else {
          assert.object(index, 'opts.index');
      }
  
      var log = _createLogger(opts.log);
      log.trace({index: index, username: opts.username,
          password: (opts.password ? '(censored)' : '(none)'),
          scope: opts.scope, insecure: opts.insecure}, 'login');
  
      var scope = opts.scope || '';
      var authInfo;
      var context = {
          pingErr: opts.pingErr
      };
  
      vasync.pipeline({arg: context, funcs: [
          function ensureChalHeader(ctx, next) {
              if (opts.pingRes) {
                  ctx.chalHeader = opts.pingRes.headers['www-authenticate'];
                  if (ctx.chalHeader) {
                      return next();
                  }
              }
              ping(opts, function (err, _, res, req) {
                  if (!err) {
                      assert.equal(res.statusCode, 200,
                          'ping success without 200');
                      // No authorization is necessary.
                      authInfo = {};
                      next(true);  // early pipeline abort
                  } else if (res && res.statusCode === 401) {
                      var chalHeader = res.headers['www-authenticate'];
  
                      // DOCKER-627 hack for quay.io
                      if (!chalHeader && req._headers.host === 'quay.io') {
                          /* JSSTYLED */
                          chalHeader = 'Bearer realm="https://quay.io/v2/auth",service="quay.io"';
                      }
  
                      if (!chalHeader) {
                          next(new errors.UnauthorizedError(
                              'missing WWW-Authenticate header in 401 ' +
                              'response to "GET /v2/" (see ' +
                              /* JSSTYLED */
                              'https://docs.docker.com/registry/spec/api/#api-version-check)'));
                          return;
                      }
  
                      ctx.pingErr = err;
                      ctx.chalHeader = chalHeader;
                      next();
                  } else {
                      next(err);
                  }
              });
          },
  
          function parseAuthChallenge(ctx, next) {
              try {
                  ctx.authChallenge = _parseWWWAuthenticate(ctx.chalHeader);
              } catch (chalErr) {
                  return next(new errors.UnauthorizedError(chalErr));
              }
              next();
          },
  
          function basicAuth(ctx, next) {
              if (ctx.authChallenge.scheme.toLowerCase() !== 'basic') {
                  return next();
              }
  
              authInfo = {
                  type: 'basic',
                  username: opts.username,
                  password: opts.password
              };
              next(true);
          },
  
          function bearerAuth(ctx, next) {
              if (ctx.authChallenge.scheme.toLowerCase() !== 'bearer') {
                  return next();
              }
              log.debug({challenge: ctx.authChallenge},
                  'login: get Bearer auth token');
  
              _getToken({
                  indexName: index.name,
                  realm: ctx.authChallenge.parms.realm,
                  service: ctx.authChallenge.parms.service,
                  scopes: scope ? [scope] : [],
                  username: opts.username,
                  password: opts.password,
                  // HTTP client opts:
                  log: log,
                  agent: opts.agent,
                  proxy: opts.proxy,
                  userAgent: opts.userAgent,
                  insecure: opts.insecure
              }, function (err, token) {
                  if (err) {
                      return next(err);
                  }
                  log.debug({token: token}, 'login: Bearer auth token');
                  authInfo = {
                      type: 'bearer',
                      token: token
                  };
                  next(true); // early pipeline abort
              });
          },
  
          function unknownAuthScheme(ctx, next) {
              next(new errors.UnauthorizedError('unsupported auth scheme: "%s"',
                  ctx.authChallenge.scheme));
          }
  
      ]}, function (err) {
          if (err === true) { // early abort
              err = null;
          }
          log.trace({err: err, success: !err}, 'login: done');
          if (err) {
              cb(err);
          } else {
              assert.object(authInfo, 'authInfo');
              cb(null, {
                  status: 'Login Succeeded',
                  authInfo: authInfo
              });
          }
      });
  }