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


Java GSSContext.isEstablished方法代码示例

本文整理汇总了Java中org.ietf.jgss.GSSContext.isEstablished方法的典型用法代码示例。如果您正苦于以下问题:Java GSSContext.isEstablished方法的具体用法?Java GSSContext.isEstablished怎么用?Java GSSContext.isEstablished使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在org.ietf.jgss.GSSContext的用法示例。


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

示例1: authenticate

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
/**
 * {@inheritDoc}
 */
@Override
public Principal authenticate(GSSContext gssContext, boolean storeCreds) {
    if (gssContext.isEstablished()) {
        String username = null;
        GSSName name = null;
        try {
            name = gssContext.getSrcName();
        } catch (GSSException e) {
            log.warn(sm.getString("realmBase.gssNameFail"), e);
            return null;
        }
        
        username = name.toString();
        
        Principal authenticatedUser = super.authenticate(gssContext, storeCreds);
            
        return filterLockedAccounts(username, authenticatedUser);
    }
    
    // Fail in all other cases
    return null;
}
 
开发者ID:liaokailin,项目名称:tomcat7,代码行数:26,代码来源:LockOutRealm.java

示例2: authenticate

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
/**
 * {@inheritDoc}
 */
@Override
public Principal authenticate(GSSContext gssContext, boolean storeCreds) {
	if (gssContext.isEstablished()) {
		String username = null;
		GSSName name = null;
		try {
			name = gssContext.getSrcName();
		} catch (GSSException e) {
			log.warn(sm.getString("realmBase.gssNameFail"), e);
			return null;
		}

		username = name.toString();

		Principal authenticatedUser = super.authenticate(gssContext, storeCreds);

		return filterLockedAccounts(username, authenticatedUser);
	}

	// Fail in all other cases
	return null;
}
 
开发者ID:how2j,项目名称:lazycat,代码行数:26,代码来源:LockOutRealm.java

示例3: processToken

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
/**
 * Process Kerberos token and get user name.
 *
 * @param gssToken GSS token
 * @return username Username of the logged in user if GSSToken can be decrypted correctly else return null
 * @throws GSSException
 */
public static String processToken(byte[] gssToken, GSSCredential gssCredentials) throws GSSException {
    GSSContext context = gssManager.createContext(gssCredentials);
    // Decrypt the kerberos ticket (GSS token)
    context.acceptSecContext(gssToken, 0, gssToken.length);

    // If we cannot decrypt the GSS Token properly we return the username as null.
    if (!context.isEstablished()) {
        log.error("Unable to decrypt the kerberos ticket as context was not established.");
        return null;
    }

    String loggedInUserName = context.getSrcName().toString();
    String target = context.getTargName().toString();

    if (log.isDebugEnabled()) {
        String msg = "Extracted details from GSS Token, LoggedIn User : " + loggedInUserName
                + " , Intended target : " + target;
        log.debug(msg);
    }

    return loggedInUserName;
}
 
开发者ID:wso2-extensions,项目名称:identity-local-auth-iwa-kerberos,代码行数:30,代码来源:IWAAuthenticationUtil.java

示例4: getUsernameFromGSSContext

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
private static String getUsernameFromGSSContext(final GSSContext gssContext, final boolean strip, final ESLogger logger) {
    if (gssContext.isEstablished()) {
        GSSName gssName = null;
        try {
            gssName = gssContext.getSrcName();
        } catch (final GSSException e) {
            logger.error("Unable to get src name from gss context", e);
        }

        if (gssName != null) {
            String name = gssName.toString();

            return stripRealmName(name, strip);

        }
    }

    return null;
}
 
开发者ID:codecentric,项目名称:elasticsearch-shield-kerberos-realm,代码行数:20,代码来源:KerberosRealm.java

示例5: GSSAuthentication

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
public GSSAuthentication(byte[] token) throws GSSException {
	GSSManager gssManager = GSSManager.getInstance();
	GSSCredential gssCreds = gssManager.createCredential(
			(GSSName) null, GSSCredential.INDEFINITE_LIFETIME,
			(Oid) null, GSSCredential.ACCEPT_ONLY);
	GSSContext gssContext = gssManager.createContext(gssCreds);

	responseToken = gssContext
			.acceptSecContext(token, 0, token.length);

	if (gssContext.isEstablished()) {
		GSSName name = gssContext.getSrcName();
		username = name.toString();
	}
}
 
开发者ID:cbsit,项目名称:JaasLounge,代码行数:16,代码来源:GSSAuthentication.java

示例6: getUsernameFromGSSContext

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
private String getUsernameFromGSSContext(final GSSContext gssContext, final boolean strip) {
    if (gssContext.isEstablished()) {
        GSSName gssName = null;
        try {
            gssName = gssContext.getSrcName();
        } catch (final GSSException e) {
            log.warn("realmBase.gssNameFail", e);
        }

        if (gssName != null) {
            String name = gssName.toString();

            if (strip && name != null) {
                final int i = name.indexOf('@');
                if (i > 0) {
                    // Zero so we don;t leave a zero length name
                    name = name.substring(0, i);
                }
            }

            return name;

        }
    }

    return null;
}
 
开发者ID:petalmd,项目名称:armor,代码行数:28,代码来源:HTTPSpnegoAuthenticator.java

示例7: authenticate

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
/**
 * {@inheritDoc}
 */
@Override
public Principal authenticate(GSSContext gssContext, boolean storeCreds) {
    if (gssContext.isEstablished()) {
        String username = null;
        GSSName name = null;
        try {
            name = gssContext.getSrcName();
        } catch (GSSException e) {
            log.warn(sm.getString("realmBase.gssNameFail"), e);
            return null;
        }
        
        username = name.toString();
        
        if (isLocked(username)) {
            // Trying to authenticate a locked user is an automatic failure
            registerAuthFailure(username);
            
            log.warn(sm.getString("lockOutRealm.authLockedUser", username));
            return null;
        }

        Principal authenticatedUser =
                super.authenticate(gssContext, storeCreds);
        
        if (authenticatedUser == null) {
            registerAuthFailure(username);
        } else {
            registerAuthSuccess(username);
        }
        return authenticatedUser;
    }
    
    // Fail in all other cases
    return null;
}
 
开发者ID:deathspeeder,项目名称:class-guard,代码行数:40,代码来源:LockOutRealm.java

示例8: encodeGSSAPIAuthenticationPacket

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
/**
 * Encodes the authentication packet for supported authentication methods.
 * 
 * @param request the socks proxy request data
 * @return the encoded buffer
 * @throws GSSException when something fails while using GSSAPI
 */
private IoBuffer encodeGSSAPIAuthenticationPacket(final SocksProxyRequest request) throws GSSException {
    GSSContext ctx = (GSSContext) getSession().getAttribute(GSS_CONTEXT);
    if (ctx == null) {
        // first step in the authentication process
        GSSManager manager = GSSManager.getInstance();
        GSSName serverName = manager.createName(request.getServiceKerberosName(), null);
        Oid krb5OID = new Oid(SocksProxyConstants.KERBEROS_V5_OID);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Available mechs:");
            for (Oid o : manager.getMechs()) {
                if (o.equals(krb5OID)) {
                    LOGGER.debug("Found Kerberos V OID available");
                }
                LOGGER.debug("{} with oid = {}", manager.getNamesForMech(o), o);
            }
        }

        ctx = manager.createContext(serverName, krb5OID, null, GSSContext.DEFAULT_LIFETIME);

        ctx.requestMutualAuth(true); // Mutual authentication
        ctx.requestConf(false);
        ctx.requestInteg(false);

        getSession().setAttribute(GSS_CONTEXT, ctx);
    }

    byte[] token = (byte[]) getSession().getAttribute(GSS_TOKEN);
    if (token != null) {
        LOGGER.debug("  Received Token[{}] = {}", token.length, ByteUtilities.asHex(token));
    }
    IoBuffer buf = null;

    if (!ctx.isEstablished()) {
        // token is ignored on the first call
        if (token == null) {
            token = new byte[32];
        }

        token = ctx.initSecContext(token, 0, token.length);

        // Send a token to the server if one was generated by
        // initSecContext
        if (token != null) {
            LOGGER.debug("  Sending Token[{}] = {}", token.length, ByteUtilities.asHex(token));

            getSession().setAttribute(GSS_TOKEN, token);
            buf = IoBuffer.allocate(4 + token.length);
            buf.put(new byte[] { SocksProxyConstants.GSSAPI_AUTH_SUBNEGOTIATION_VERSION,
                    SocksProxyConstants.GSSAPI_MSG_TYPE });

            buf.put(ByteUtilities.intToNetworkByteOrder(token.length, 2));
            buf.put(token);
        }
    }

    return buf;
}
 
开发者ID:eclipse,项目名称:neoscada,代码行数:66,代码来源:Socks5LogicHandler.java

示例9: authenticate

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
/**
 * {@inheritDoc}
 */
@Override
public Principal authenticate(GSSContext gssContext, boolean storeCreds) {
    if (gssContext.isEstablished()) {
        Principal authenticatedUser = null;
        String username = null;
        
        GSSName name = null;
        try {
            name = gssContext.getSrcName();
        } catch (GSSException e) {
            log.warn(sm.getString("realmBase.gssNameFail"), e);
            return null;
        }
        
        username = name.toString();

        for (Realm realm : realms) {
            if (log.isDebugEnabled()) {
                log.debug(sm.getString("combinedRealm.authStart",
                        username, realm.getInfo()));
            }

            authenticatedUser = realm.authenticate(gssContext, storeCreds);

            if (authenticatedUser == null) {
                if (log.isDebugEnabled()) {
                    log.debug(sm.getString("combinedRealm.authFail",
                            username, realm.getInfo()));
                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug(sm.getString("combinedRealm.authSuccess",
                            username, realm.getInfo()));
                }
                break;
            }
        }
        return authenticatedUser;
    }
    
    // Fail in all other cases
    return null;
}
 
开发者ID:liaokailin,项目名称:tomcat7,代码行数:47,代码来源:CombinedRealm.java

示例10: login

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
@Override public UserIdentity login(String username, Object credentials) {
  String encodedAuthToken = (String) credentials;
  byte[] authToken = B64Code.decode(encodedAuthToken);

  GSSManager manager = GSSManager.getInstance();
  try {
    // http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html
    Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
    Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
    GSSName gssName = manager.createName(serverPrincipal, null);
    // CALCITE-1922 Providing both OIDs is the bug in Jetty we're working around. By specifying
    // only one, we're requiring that clients *must* provide us the SPNEGO OID to authenticate
    // via Kerberos which is wrong. Best as I can tell, the SPNEGO OID is meant as another
    // layer of indirection (essentially is equivalent to setting the Kerberos OID).
    GSSCredential serverCreds = manager.createCredential(gssName,
        GSSCredential.INDEFINITE_LIFETIME, new Oid[] {krb5Oid, spnegoOid},
        GSSCredential.ACCEPT_ONLY);
    GSSContext gContext = manager.createContext(serverCreds);

    if (gContext == null) {
      LOG.debug("SpnegoUserRealm: failed to establish GSSContext");
    } else {
      while (!gContext.isEstablished()) {
        authToken = gContext.acceptSecContext(authToken, 0, authToken.length);
      }
      if (gContext.isEstablished()) {
        String clientName = gContext.getSrcName().toString();
        String role = clientName.substring(clientName.indexOf('@') + 1);

        LOG.debug("SpnegoUserRealm: established a security context");
        LOG.debug("Client Principal is: {}", gContext.getSrcName());
        LOG.debug("Server Principal is: {}", gContext.getTargName());
        LOG.debug("Client Default Role: {}", role);

        SpnegoUserPrincipal user = new SpnegoUserPrincipal(clientName, authToken);

        Subject subject = new Subject();
        subject.getPrincipals().add(user);

        return _identityService.newUserIdentity(subject, user, new String[]{role});
      }
    }
  } catch (GSSException gsse) {
    LOG.warn("Caught GSSException trying to authenticate the client", gsse);
  }

  return null;
}
 
开发者ID:apache,项目名称:calcite-avatica,代码行数:49,代码来源:PropertyBasedSpnegoLoginService.java

示例11: authenticate

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
/**
 * {@inheritDoc}
 */
@Override
public Principal authenticate(GSSContext gssContext, boolean storeCreds) {
	if (gssContext.isEstablished()) {
		Principal authenticatedUser = null;
		String username = null;

		GSSName name = null;
		try {
			name = gssContext.getSrcName();
		} catch (GSSException e) {
			log.warn(sm.getString("realmBase.gssNameFail"), e);
			return null;
		}

		username = name.toString();

		for (Realm realm : realms) {
			if (log.isDebugEnabled()) {
				log.debug(sm.getString("combinedRealm.authStart", username, realm.getInfo()));
			}

			authenticatedUser = realm.authenticate(gssContext, storeCreds);

			if (authenticatedUser == null) {
				if (log.isDebugEnabled()) {
					log.debug(sm.getString("combinedRealm.authFail", username, realm.getInfo()));
				}
			} else {
				if (log.isDebugEnabled()) {
					log.debug(sm.getString("combinedRealm.authSuccess", username, realm.getInfo()));
				}
				break;
			}
		}
		return authenticatedUser;
	}

	// Fail in all other cases
	return null;
}
 
开发者ID:how2j,项目名称:lazycat,代码行数:44,代码来源:CombinedRealm.java

示例12: doSpnegoAuth

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
/**
 * Performs authentication using the SPNEGO mechanism.
 *
 * <p>
 * Returns null if authentication failed or if the provided 
 * the auth scheme did not contain the SPNEGO/GSS token.
 * </p>
 * 
 * @return SpnegoPrincipal for the given auth scheme.
 */
private SpnegoPrincipal doSpnegoAuth(
    final SpnegoAuthScheme scheme, final SpnegoHttpServletResponse resp) 
    throws GSSException, IOException {

    final String principal;
    final byte[] gss = scheme.getToken();

    if (0 == gss.length) {
        LOGGER.finer("GSS data was NULL.");
        return null;
    }

    GSSContext context = null;
    GSSCredential delegCred = null;
    
    try {
        byte[] token = null;
        
        SpnegoAuthenticator.LOCK.lock();
        try {
            context = SpnegoAuthenticator.MANAGER.createContext(this.serverCredentials);
            token = context.acceptSecContext(gss, 0, gss.length);
        } finally {
            SpnegoAuthenticator.LOCK.unlock();
        }

        if (null == token) {
            LOGGER.finer("Token was NULL.");
            return null;
        }

        resp.setHeader(Constants.AUTHN_HEADER, Constants.NEGOTIATE_HEADER 
                + ' ' + Base64.encode(token));

        if (!context.isEstablished()) {
            LOGGER.fine("context not established");
            resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED, true);
            return null;
        }

        principal = context.getSrcName().toString();
        
        if (this.allowDelegation && context.getCredDelegState()) {
            delegCred = context.getDelegCred();
        }

    } finally {
        if (null != context) {
            SpnegoAuthenticator.LOCK.lock();
            try {
                context.dispose();
            } finally {
                SpnegoAuthenticator.LOCK.unlock();
            }
        }
    }

    return new SpnegoPrincipal(principal, KerberosPrincipal.KRB_NT_PRINCIPAL, delegCred);
}
 
开发者ID:codelibs,项目名称:spnego,代码行数:70,代码来源:SpnegoAuthenticator.java

示例13: spnegoLogin

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
private UserIdentity spnegoLogin(Object credentials) {

    String encodedAuthToken = (String) credentials;
    byte[] authToken = B64Code.decode(encodedAuthToken);
    GSSManager manager = GSSManager.getInstance();

    try {
      // Providing both OID's is required here. If we provide only one,
      // we're requiring that clients provide us the SPNEGO OID to authenticate via Kerberos.
      Oid[] knownOids = new Oid[2];
      knownOids[0] = new Oid("1.3.6.1.5.5.2"); // spnego
      knownOids[1] = new Oid("1.2.840.113554.1.2.2"); // kerberos

      GSSName gssName = manager.createName(spnegoConfig.getSpnegoPrincipal(), null);
      GSSCredential serverCreds = manager.createCredential(gssName, GSSCredential.INDEFINITE_LIFETIME,
          knownOids, GSSCredential.ACCEPT_ONLY);
      GSSContext gContext = manager.createContext(serverCreds);

      if (gContext == null) {
        logger.debug("SPNEGOUserRealm: failed to establish GSSContext");
      } else {
        while (!gContext.isEstablished()) {
          authToken = gContext.acceptSecContext(authToken, 0, authToken.length);
        }

        if (gContext.isEstablished()) {
          String clientName = gContext.getSrcName().toString();
          String role = clientName.substring(clientName.indexOf(64) + 1);

          final SystemOptionManager sysOptions = drillContext.getOptionManager();
          final boolean isAdmin = ImpersonationUtil.hasAdminPrivileges(role,
              ExecConstants.ADMIN_USERS_VALIDATOR.getAdminUsers(sysOptions),
              ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.getAdminUserGroups(sysOptions));

          final Principal user = new DrillUserPrincipal(clientName, isAdmin);
          final Subject subject = new Subject();
          subject.getPrincipals().add(user);

          if (isAdmin) {
            return this._identityService.newUserIdentity(subject, user, DrillUserPrincipal.ADMIN_USER_ROLES);
          } else {
            return this._identityService.newUserIdentity(subject, user, DrillUserPrincipal.NON_ADMIN_USER_ROLES);
          }
        }
      }
    } catch (GSSException gsse) {
      logger.warn("Caught GSSException trying to authenticate the client", gsse);
    }
    return null;
  }
 
开发者ID:axbaretto,项目名称:drill,代码行数:51,代码来源:DrillSpnegoLoginService.java

示例14: getGSSContext

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
private GSSContext getGSSContext(final GssAciServerDetails serverDetails) throws AciHttpException, IOException {
    LOGGER.trace("getGSSContext() called...");

    try {
        LOGGER.debug("Setting up to try and create a GSSContext...");

        // Krb5 Oids, see RFC 1964...
        final Oid krb5Mechanism = new Oid("1.2.840.113554.1.2.2");
        final Oid krb5PrincipalNameType = new Oid("1.2.840.113554.1.2.2.1");

        // Prepare stuff for setting up the context...
        final GSSManager manager = GSSManager.getInstance();
        final GSSName serverName = manager.createName(serverDetails.getServiceName(), krb5PrincipalNameType);

        // Set up the context...
        final GSSContext context = manager.createContext(serverName, krb5Mechanism, null, GSSContext.DEFAULT_LIFETIME);
        context.requestConf(true);
        context.requestMutualAuth(true);
        context.requestReplayDet(true);
        context.requestSequenceDet(true);

        // Do the context establishment loop...
        byte[] token = EMPTY_BYTE_ARRAY;

        while (!context.isEstablished()) {
            // token is ignored on the first call
            token = context.initSecContext(token, 0, token.length);

            if (token != null) {
                LOGGER.debug("Sending GSS action to the ACI server for context token...");

                // Build the parameter set...
                final ActionParameters parameters = new ActionParameters();
                parameters.add(AciConstants.PARAM_ACTION, "GSS");
                parameters.add("gssServiceName", new String(Base64.encodeBase64(token), "UTF-8"));

                // Execute the action and process the response...
                final AciResponseInputStream response = super.executeAction(serverDetails, parameters);
                token = new GssContextTokenProcessor().process(response);

                // Ensure that we close the stream to release the connection, otherwise another will be used and the
                // subsequent action will fail as it wasn't made on the same connection as this token exchange...
                IOUtils.getInstance().closeQuietly(response);
            }
        }

        // display context information
        LOGGER.debug("Successfully established a GSSContext...");
        LOGGER.debug("Remaining lifetime in seconds = {}", context.getLifetime());
        LOGGER.debug("Context mechanism             = {}", context.getMech());
        LOGGER.debug("Initiator                     = {}", context.getSrcName());
        LOGGER.debug("Acceptor                      = {}", context.getTargName());

        // Return the context...
        return context;
    } catch (final GSSException gsse) {
        throw new AciHttpException("Unable to establish a GSSContext.", gsse);
    } catch (final UnsupportedEncodingException uee) {
        throw new AciHttpException("Unable to establish a GSSContext due to an unsupported encoding.", uee);
    } catch (final ProcessorException pe) {
        throw new AciHttpException("Unable to parse the context response.", pe);
    } catch (final AciErrorException aee) {
        throw new AciHttpException("Unable to establish a GSSContext with the ACI Server.", aee);
    }
}
 
开发者ID:hpe-idol,项目名称:java-aci-api-ng,代码行数:66,代码来源:GssAciHttpClientImpl.java

示例15: runWithPrincipal

import org.ietf.jgss.GSSContext; //导入方法依赖的package包/类
private AuthenticationToken runWithPrincipal(String serverPrincipal,
    byte[] clientToken, Base64 base64, HttpServletResponse response) throws
    IOException, AuthenticationException, ClassNotFoundException,
    GSSException, IllegalAccessException, NoSuchFieldException {
  GSSContext gssContext = null;
  GSSCredential gssCreds = null;
  AuthenticationToken token = null;
  try {
    LOG.trace("SPNEGO initiated with server principal [{}]", serverPrincipal);
    gssCreds = this.gssManager.createCredential(
        this.gssManager.createName(serverPrincipal,
            KerberosUtil.getOidInstance("NT_GSS_KRB5_PRINCIPAL")),
        GSSCredential.INDEFINITE_LIFETIME,
        new Oid[]{
            KerberosUtil.getOidInstance("GSS_SPNEGO_MECH_OID"),
            KerberosUtil.getOidInstance("GSS_KRB5_MECH_OID")},
        GSSCredential.ACCEPT_ONLY);
    gssContext = this.gssManager.createContext(gssCreds);
    byte[] serverToken = gssContext.acceptSecContext(clientToken, 0,
        clientToken.length);
    if (serverToken != null && serverToken.length > 0) {
      String authenticate = base64.encodeToString(serverToken);
      response.setHeader(KerberosAuthenticator.WWW_AUTHENTICATE,
                         KerberosAuthenticator.NEGOTIATE + " " +
                         authenticate);
    }
    if (!gssContext.isEstablished()) {
      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
      LOG.trace("SPNEGO in progress");
    } else {
      String clientPrincipal = gssContext.getSrcName().toString();
      KerberosName kerberosName = new KerberosName(clientPrincipal);
      String userName = kerberosName.getShortName();
      token = new AuthenticationToken(userName, clientPrincipal, getType());
      response.setStatus(HttpServletResponse.SC_OK);
      LOG.trace("SPNEGO completed for client principal [{}]",
          clientPrincipal);
    }
  } finally {
    if (gssContext != null) {
      gssContext.dispose();
    }
    if (gssCreds != null) {
      gssCreds.dispose();
    }
  }
  return token;
}
 
开发者ID:hopshadoop,项目名称:hops,代码行数:49,代码来源:KerberosAuthenticationHandler.java


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