当前位置: 首页>>代码示例>>Java>>正文


Java RpcErrorCodeProto.FATAL_UNAUTHORIZED属性代码示例

本文整理汇总了Java中org.apache.hadoop.ipc.protobuf.RpcHeaderProtos.RpcResponseHeaderProto.RpcErrorCodeProto.FATAL_UNAUTHORIZED属性的典型用法代码示例。如果您正苦于以下问题:Java RpcErrorCodeProto.FATAL_UNAUTHORIZED属性的具体用法?Java RpcErrorCodeProto.FATAL_UNAUTHORIZED怎么用?Java RpcErrorCodeProto.FATAL_UNAUTHORIZED使用的例子?那么恭喜您, 这里精选的属性代码示例或许可以为您提供帮助。您也可以进一步了解该属性所在org.apache.hadoop.ipc.protobuf.RpcHeaderProtos.RpcResponseHeaderProto.RpcErrorCodeProto的用法示例。


在下文中一共展示了RpcErrorCodeProto.FATAL_UNAUTHORIZED属性的11个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Java代码示例。

示例1: authorizeConnection

/**
 * Authorize proxy users to access this server
 * @throws WrappedRpcServerException - user is not allowed to proxy
 */
private void authorizeConnection() throws WrappedRpcServerException {
  try {
    // If auth method is TOKEN, the token was obtained by the
    // real user for the effective user, therefore not required to
    // authorize real user. doAs is allowed only for simple or kerberos
    // authentication
    if (user != null && user.getRealUser() != null
        && (authMethod != AuthMethod.TOKEN)) {
      ProxyUsers.authorize(user, this.getHostAddress());
    }
    authorize(user, protocolName, getHostInetAddress());
    if (LOG.isDebugEnabled()) {
      LOG.debug("Successfully authorized " + connectionContext);
    }
    rpcMetrics.incrAuthorizationSuccesses();
  } catch (AuthorizationException ae) {
    LOG.info("Connection from " + this
        + " for protocol " + connectionContext.getProtocol()
        + " is unauthorized for user " + user);
    rpcMetrics.incrAuthorizationFailures();
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_UNAUTHORIZED, ae);
  }
}
 
开发者ID:nucypher,项目名称:hadoop-oss,代码行数:28,代码来源:Server.java

示例2: authorizeConnection

/**
 * Authorize proxy users to access this server
 * @throws WrappedRpcServerException - user is not allowed to proxy
 */
private void authorizeConnection() throws WrappedRpcServerException {
  try {
    // If auth method is TOKEN, the token was obtained by the
    // real user for the effective user, therefore not required to
    // authorize real user. doAs is allowed only for simple or kerberos
    // authentication
    if (user != null && user.getRealUser() != null
        && (authMethod != AuthMethod.TOKEN)) {
      ProxyUsers.authorize(user, this.getHostAddress(), conf);
    }
    authorize(user, protocolName, getHostInetAddress());
    if (LOG.isDebugEnabled()) {
      LOG.debug("Successfully authorized " + connectionContext);
    }
    rpcMetrics.incrAuthorizationSuccesses();
  } catch (AuthorizationException ae) {
    LOG.info("Connection from " + this
        + " for protocol " + connectionContext.getProtocol()
        + " is unauthorized for user " + user);
    rpcMetrics.incrAuthorizationFailures();
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_UNAUTHORIZED, ae);
  }
}
 
开发者ID:ict-carch,项目名称:hadoop-plus,代码行数:28,代码来源:Server.java

示例3: authorizeConnection

/**
 * Authorize proxy users to access this server
 * @throws RpcServerException - user is not allowed to proxy
 */
private void authorizeConnection() throws RpcServerException {
  try {
    // If auth method is TOKEN, the token was obtained by the
    // real user for the effective user, therefore not required to
    // authorize real user. doAs is allowed only for simple or kerberos
    // authentication
    if (user != null && user.getRealUser() != null
        && (authMethod != AuthMethod.TOKEN)) {
      ProxyUsers.authorize(user, this.getHostAddress());
    }
    authorize(user, protocolName, getHostInetAddress());
    if (LOG.isDebugEnabled()) {
      LOG.debug("Successfully authorized " + connectionContext);
    }
    rpcMetrics.incrAuthorizationSuccesses();
  } catch (AuthorizationException ae) {
    LOG.info("Connection from " + this
        + " for protocol " + connectionContext.getProtocol()
        + " is unauthorized for user " + user);
    rpcMetrics.incrAuthorizationFailures();
    throw new FatalRpcServerException(
        RpcErrorCodeProto.FATAL_UNAUTHORIZED, ae);
  }
}
 
开发者ID:hopshadoop,项目名称:hops,代码行数:28,代码来源:Server.java

示例4: saslProcess

/**
 * Process saslMessage and send saslResponse back
 * @param saslMessage received SASL message
 * @throws WrappedRpcServerException setup failed due to SASL negotiation 
 *         failure, premature or invalid connection context, or other state 
 *         errors. This exception needs to be sent to the client. This 
 *         exception will wrap {@link RetriableException}, 
 *         {@link InvalidToken}, {@link StandbyException} or 
 *         {@link SaslException}.
 * @throws IOException if sending reply fails
 * @throws InterruptedException
 */
private void saslProcess(RpcSaslProto saslMessage)
    throws WrappedRpcServerException, IOException, InterruptedException {
  if (saslContextEstablished) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,
        new SaslException("Negotiation is already complete"));
  }
  RpcSaslProto saslResponse = null;
  try {
    try {
      saslResponse = processSaslMessage(saslMessage);
    } catch (IOException e) {
      rpcMetrics.incrAuthenticationFailures();
      if (LOG.isDebugEnabled()) {
        LOG.debug(StringUtils.stringifyException(e));
      }
      // attempting user could be null
      IOException tce = (IOException) getTrueCause(e);
      AUDITLOG.warn(AUTH_FAILED_FOR + this.toString() + ":"
          + attemptingUser + " (" + e.getLocalizedMessage()
          + ") with true cause: (" + tce.getLocalizedMessage() + ")");
      throw tce;
    }
    
    if (saslServer != null && saslServer.isComplete()) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server context established. Negotiated QoP is "
            + saslServer.getNegotiatedProperty(Sasl.QOP));
      }
      user = getAuthorizedUgi(saslServer.getAuthorizationID());
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server successfully authenticated client: " + user);
      }
      rpcMetrics.incrAuthenticationSuccesses();
      AUDITLOG.info(AUTH_SUCCESSFUL_FOR + user);
      saslContextEstablished = true;
    }
  } catch (WrappedRpcServerException wrse) { // don't re-wrap
    throw wrse;
  } catch (IOException ioe) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_UNAUTHORIZED, ioe);
  }
  // send back response if any, may throw IOException
  if (saslResponse != null) {
    doSaslReply(saslResponse);
  }
  // do NOT enable wrapping until the last auth response is sent
  if (saslContextEstablished) {
    String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
    // SASL wrapping is only used if the connection has a QOP, and
    // the value is not auth.  ex. auth-int & auth-priv
    useWrap = (qop != null && !"auth".equalsIgnoreCase(qop));        
  }
}
 
开发者ID:nucypher,项目名称:hadoop-oss,代码行数:67,代码来源:Server.java

示例5: processConnectionContext

/** Reads the connection context following the connection header
 * @param dis - DataInputStream from which to read the header 
 * @throws WrappedRpcServerException - if the header cannot be
 *         deserialized, or the user is not authorized
 */ 
private void processConnectionContext(DataInputStream dis)
    throws WrappedRpcServerException {
  // allow only one connection context during a session
  if (connectionContextRead) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,
        "Connection context already processed");
  }
  connectionContext = decodeProtobufFromStream(
      IpcConnectionContextProto.newBuilder(), dis);
  protocolName = connectionContext.hasProtocol() ? connectionContext
      .getProtocol() : null;

  UserGroupInformation protocolUser = ProtoUtil.getUgi(connectionContext);
  if (saslServer == null) {
    user = protocolUser;
  } else {
    // user is authenticated
    user.setAuthenticationMethod(authMethod);
    //Now we check if this is a proxy user case. If the protocol user is
    //different from the 'user', it is a proxy user scenario. However, 
    //this is not allowed if user authenticated with DIGEST.
    if ((protocolUser != null)
        && (!protocolUser.getUserName().equals(user.getUserName()))) {
      if (authMethod == AuthMethod.TOKEN) {
        // Not allowed to doAs if token authentication is used
        throw new WrappedRpcServerException(
            RpcErrorCodeProto.FATAL_UNAUTHORIZED,
            new AccessControlException("Authenticated user (" + user
                + ") doesn't match what the client claims to be ("
                + protocolUser + ")"));
      } else {
        // Effective user can be different from authenticated user
        // for simple auth or kerberos auth
        // The user is the real user. Now we create a proxy user
        UserGroupInformation realUser = user;
        user = UserGroupInformation.createProxyUser(protocolUser
            .getUserName(), realUser);
      }
    }
  }
  authorizeConnection();
  // don't set until after authz because connection isn't established
  connectionContextRead = true;
}
 
开发者ID:nucypher,项目名称:hadoop-oss,代码行数:50,代码来源:Server.java

示例6: saslProcess

private void saslProcess(RpcSaslProto saslMessage)
    throws WrappedRpcServerException, IOException, InterruptedException {
  if (saslContextEstablished) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,
        new SaslException("Negotiation is already complete"));
  }
  RpcSaslProto saslResponse = null;
  try {
    try {
      saslResponse = processSaslMessage(saslMessage);
    } catch (IOException e) {
      rpcMetrics.incrAuthenticationFailures();
      // attempting user could be null
      AUDITLOG.warn(AUTH_FAILED_FOR + this.toString() + ":"
          + attemptingUser + " (" + e.getLocalizedMessage() + ")");
      throw (IOException) getCauseForInvalidToken(e);
    }
    
    if (saslServer != null && saslServer.isComplete()) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server context established. Negotiated QoP is "
            + saslServer.getNegotiatedProperty(Sasl.QOP));
      }
      user = getAuthorizedUgi(saslServer.getAuthorizationID());
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server successfully authenticated client: " + user);
      }
      rpcMetrics.incrAuthenticationSuccesses();
      AUDITLOG.info(AUTH_SUCCESSFUL_FOR + user);
      saslContextEstablished = true;
    }
  } catch (WrappedRpcServerException wrse) { // don't re-wrap
    throw wrse;
  } catch (IOException ioe) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_UNAUTHORIZED, ioe);
  }
  // send back response if any, may throw IOException
  if (saslResponse != null) {
    doSaslReply(saslResponse);
  }
  // do NOT enable wrapping until the last auth response is sent
  if (saslContextEstablished) {
    String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
    // SASL wrapping is only used if the connection has a QOP, and
    // the value is not auth.  ex. auth-int & auth-priv
    useWrap = (qop != null && !"auth".equalsIgnoreCase(qop));        
  }
}
 
开发者ID:naver,项目名称:hadoop,代码行数:50,代码来源:Server.java

示例7: saslProcess

private void saslProcess(RpcSaslProto saslMessage)
    throws WrappedRpcServerException, IOException, InterruptedException {
  if (saslContextEstablished) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,
        new SaslException("Negotiation is already complete"));
  }
  RpcSaslProto saslResponse = null;
  try {
    try {
      saslResponse = processSaslMessage(saslMessage);
    } catch (IOException e) {
      rpcMetrics.incrAuthenticationFailures();
      if (LOG.isDebugEnabled()) {
        LOG.debug(StringUtils.stringifyException(e));
      }
      // attempting user could be null
      IOException tce = (IOException) getCauseForInvalidToken(e);
      AUDITLOG.warn(AUTH_FAILED_FOR + this.toString() + ":"
          + attemptingUser + " (" + e.getLocalizedMessage()
          + ") with true cause: (" + tce.getLocalizedMessage() + ")");
      throw tce;
    }
    
    if (saslServer != null && saslServer.isComplete()) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server context established. Negotiated QoP is "
            + saslServer.getNegotiatedProperty(Sasl.QOP));
      }
      user = getAuthorizedUgi(saslServer.getAuthorizationID());
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server successfully authenticated client: " + user);
      }
      rpcMetrics.incrAuthenticationSuccesses();
      AUDITLOG.info(AUTH_SUCCESSFUL_FOR + user);
      saslContextEstablished = true;
    }
  } catch (WrappedRpcServerException wrse) { // don't re-wrap
    throw wrse;
  } catch (IOException ioe) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_UNAUTHORIZED, ioe);
  }
  // send back response if any, may throw IOException
  if (saslResponse != null) {
    doSaslReply(saslResponse);
  }
  // do NOT enable wrapping until the last auth response is sent
  if (saslContextEstablished) {
    String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
    // SASL wrapping is only used if the connection has a QOP, and
    // the value is not auth.  ex. auth-int & auth-priv
    useWrap = (qop != null && !"auth".equalsIgnoreCase(qop));        
  }
}
 
开发者ID:Nextzero,项目名称:hadoop-2.6.0-cdh5.4.3,代码行数:55,代码来源:Server.java

示例8: saslProcess

private void saslProcess(RpcSaslProto saslMessage)
    throws WrappedRpcServerException, IOException, InterruptedException {
  if (saslContextEstablished) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,
        new SaslException("Negotiation is already complete"));
  }
  RpcSaslProto saslResponse = null;
  try {
    try {
      saslResponse = processSaslMessage(saslMessage);
    } catch (IOException e) {
      IOException sendToClient = e;
      Throwable cause = e;
      while (cause != null) {
        if (cause instanceof InvalidToken) {
          sendToClient = (InvalidToken) cause;
          break;
        }
        cause = cause.getCause();
      }
      rpcMetrics.incrAuthenticationFailures();
      String clientIP = this.toString();
      // attempting user could be null
      AUDITLOG.warn(AUTH_FAILED_FOR + clientIP + ":" + attemptingUser +
        " (" + e.getLocalizedMessage() + ")");
      throw sendToClient;
    }
    
    if (saslServer != null && saslServer.isComplete()) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server context established. Negotiated QoP is "
            + saslServer.getNegotiatedProperty(Sasl.QOP));
      }
      user = getAuthorizedUgi(saslServer.getAuthorizationID());
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server successfully authenticated client: " + user);
      }
      rpcMetrics.incrAuthenticationSuccesses();
      AUDITLOG.info(AUTH_SUCCESSFUL_FOR + user);
      saslContextEstablished = true;
    }
  } catch (WrappedRpcServerException wrse) { // don't re-wrap
    throw wrse;
  } catch (IOException ioe) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_UNAUTHORIZED, ioe);
  }
  // send back response if any, may throw IOException
  if (saslResponse != null) {
    doSaslReply(saslResponse);
  }
  // do NOT enable wrapping until the last auth response is sent
  if (saslContextEstablished) {
    String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
    // SASL wrapping is only used if the connection has a QOP, and
    // the value is not auth.  ex. auth-int & auth-priv
    useWrap = (qop != null && !"auth".equalsIgnoreCase(qop));        
  }
}
 
开发者ID:ict-carch,项目名称:hadoop-plus,代码行数:60,代码来源:Server.java

示例9: saslProcess

private void saslProcess(RpcSaslProto saslMessage)
    throws RpcServerException, IOException, InterruptedException {
  if (saslContextEstablished) {
    throw new FatalRpcServerException(
        RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,
        new SaslException("Negotiation is already complete"));
  }
  RpcSaslProto saslResponse = null;
  try {
    try {
      saslResponse = processSaslMessage(saslMessage);
    } catch (IOException e) {
      rpcMetrics.incrAuthenticationFailures();
      if (LOG.isDebugEnabled()) {
        LOG.debug(StringUtils.stringifyException(e));
      }
      // attempting user could be null
      IOException tce = (IOException) getCauseForInvalidToken(e);
      AUDITLOG.warn(AUTH_FAILED_FOR + this.toString() + ":"
          + attemptingUser + " (" + e.getLocalizedMessage()
          + ") with true cause: (" + tce.getLocalizedMessage() + ")");
      throw tce;
    }
    
    if (saslServer != null && saslServer.isComplete()) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server context established. Negotiated QoP is "
            + saslServer.getNegotiatedProperty(Sasl.QOP));
      }
      user = getAuthorizedUgi(saslServer.getAuthorizationID());
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server successfully authenticated client: " + user);
      }
      rpcMetrics.incrAuthenticationSuccesses();
      AUDITLOG.info(AUTH_SUCCESSFUL_FOR + user);
      saslContextEstablished = true;
    }
  } catch (RpcServerException rse) { // don't re-wrap
    throw rse;
  } catch (IOException ioe) {
    throw new FatalRpcServerException(
        RpcErrorCodeProto.FATAL_UNAUTHORIZED, ioe);
  }
  // send back response if any, may throw IOException
  if (saslResponse != null) {
    doSaslReply(saslResponse);
  }
  // do NOT enable wrapping until the last auth response is sent
  if (saslContextEstablished) {
    String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
    // SASL wrapping is only used if the connection has a QOP, and
    // the value is not auth.  ex. auth-int & auth-priv
    useWrap = (qop != null && !"auth".equalsIgnoreCase(qop));
    if (!useWrap) {
      disposeSasl();
    }
  }
}
 
开发者ID:hopshadoop,项目名称:hops,代码行数:58,代码来源:Server.java

示例10: processConnectionContext

/** Reads the connection context following the connection header
 * @param buffer - DataInputStream from which to read the header
 * @throws RpcServerException - if the header cannot be
 *         deserialized, or the user is not authorized
 */ 
private void processConnectionContext(RpcWritable.Buffer buffer)
    throws RpcServerException {
  // allow only one connection context during a session
  if (connectionContextRead) {
    throw new FatalRpcServerException(
        RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,
        "Connection context already processed");
  }
  connectionContext = getMessage(IpcConnectionContextProto.getDefaultInstance(), buffer);
  protocolName = connectionContext.hasProtocol() ? connectionContext
      .getProtocol() : null;

  UserGroupInformation protocolUser = ProtoUtil.getUgi(connectionContext);
  if (authProtocol == AuthProtocol.NONE) {
    user = protocolUser;
    authenticateSSLConnection(protocolUser);
  } else {
    // user is authenticated
    user.setAuthenticationMethod(authMethod);
    //Now we check if this is a proxy user case. If the protocol user is
    //different from the 'user', it is a proxy user scenario. However, 
    //this is not allowed if user authenticated with DIGEST.
    if ((protocolUser != null)
        && (!protocolUser.getUserName().equals(user.getUserName()))) {
      if (authMethod == AuthMethod.TOKEN) {
        // Not allowed to doAs if token authentication is used
        throw new FatalRpcServerException(
            RpcErrorCodeProto.FATAL_UNAUTHORIZED,
            new AccessControlException("Authenticated user (" + user
                + ") doesn't match what the client claims to be ("
                + protocolUser + ")"));
      } else {
        // Effective user can be different from authenticated user
        // for simple auth or kerberos auth
        // The user is the real user. Now we create a proxy user
        UserGroupInformation realUser = user;
        user = UserGroupInformation.createProxyUser(protocolUser
            .getUserName(), realUser);
      }
    }
  }
  authorizeConnection();
  // don't set until after authz because connection isn't established
  connectionContextRead = true;
  if (user != null) {
    connectionManager.incrUserConnections(user.getShortUserName());
  }
}
 
开发者ID:hopshadoop,项目名称:hops,代码行数:53,代码来源:Server.java

示例11: saslProcess

private void saslProcess(RpcSaslProto saslMessage)
    throws WrappedRpcServerException, IOException, InterruptedException {
  if (saslContextEstablished) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,
        new SaslException("Negotiation is already complete"));
  }
  RpcSaslProto saslResponse = null;
  try {
    try {
      saslResponse = processSaslMessage(saslMessage);
    } catch (IOException e) {
      IOException sendToClient = e;
      Throwable cause = e;
      while (cause != null) {
        if (cause instanceof InvalidToken) {
          // FIXME: hadoop method signatures are restricting the SASL
          // callbacks to only returning InvalidToken, but some services
          // need to throw other exceptions (ex. NN + StandyException),
          // so for now we'll tunnel the real exceptions via an
          // InvalidToken's cause which normally is not set 
          if (cause.getCause() != null) {
            cause = cause.getCause();
          }
          sendToClient = (IOException) cause;
          break;
        }
        cause = cause.getCause();
      }
      rpcMetrics.incrAuthenticationFailures();
      String clientIP = this.toString();
      // attempting user could be null
      AUDITLOG.warn(AUTH_FAILED_FOR + clientIP + ":" + attemptingUser +
        " (" + e.getLocalizedMessage() + ")");
      throw sendToClient;
    }
    
    if (saslServer != null && saslServer.isComplete()) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server context established. Negotiated QoP is "
            + saslServer.getNegotiatedProperty(Sasl.QOP));
      }
      user = getAuthorizedUgi(saslServer.getAuthorizationID());
      if (LOG.isDebugEnabled()) {
        LOG.debug("SASL server successfully authenticated client: " + user);
      }
      rpcMetrics.incrAuthenticationSuccesses();
      AUDITLOG.info(AUTH_SUCCESSFUL_FOR + user);
      saslContextEstablished = true;
    }
  } catch (WrappedRpcServerException wrse) { // don't re-wrap
    throw wrse;
  } catch (IOException ioe) {
    throw new WrappedRpcServerException(
        RpcErrorCodeProto.FATAL_UNAUTHORIZED, ioe);
  }
  // send back response if any, may throw IOException
  if (saslResponse != null) {
    doSaslReply(saslResponse);
  }
  // do NOT enable wrapping until the last auth response is sent
  if (saslContextEstablished) {
    String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
    // SASL wrapping is only used if the connection has a QOP, and
    // the value is not auth.  ex. auth-int & auth-priv
    useWrap = (qop != null && !"auth".equalsIgnoreCase(qop));        
  }
}
 
开发者ID:chendave,项目名称:hadoop-TCP,代码行数:68,代码来源:Server.java


注:本文中的org.apache.hadoop.ipc.protobuf.RpcHeaderProtos.RpcResponseHeaderProto.RpcErrorCodeProto.FATAL_UNAUTHORIZED属性示例由纯净天空整理自Github/MSDocs等开源代码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。