序:

最近项目需求要用Ranger把Zeppelin管起来,之前聊过使用LDAP的模式,这次我们说说不使用LDAP,通过开发Ranger插件的方式将Zeppelin和Ranger继承起来

目录

序:

一、Zeppelin权限部分分析

1、zeppelin-note权限分析

2、zeppelin-shiro权限分析

二、shiro权限原理分析及Ranger原理分析

1、shiro认证授权原理

2、Ranger认证授权原理

三、自定义Ranger插件

1、编写shiroService

2、编写资源json文件

3、编写Ranger授权类

四、自定义Shiro拦截器(RangerFilter)

五、测试


一、Zeppelin权限部分分析

由官方文档可知,zeppelin权限是使用shiro接管的,认证、授权默认使用的shiro的textRealm,同时还支持LDAPRealm、PamRealm、JDBCRealm等其他Realm。

Zeppelin中的权限有两个大模块,一方面是note粒度的权限,另一方面是菜单权限粒度,解释器配置页面的访问权限、版本控制页面的访问权限以及其他一些页面url的拦截。

1、zeppelin-note权限分析

对于note粒度的权限,划分为可读可写可执行,配置的方式目前有两种:页面配置和RESTApi设置,如下图:

源码中实现过程是在org.apache.zeppelin.service.NotebookService类中,所有的note操作都要经过org.apache.zeppelin.service.NotebookService.checkPermission()方法来鉴权

  enum Permission {READER,WRITER,RUNNER,OWNER,}/*** Return null when it is allowed, otherwise return the error message which could be* propagated to frontend** @param noteId* @param context* @param permission* @param op* @return*/private <T> boolean checkPermission(String noteId,Permission permission,Message.OP op,ServiceContext context,ServiceCallback<T> callback) throws IOException {boolean isAllowed = false;Set<String> allowed = null;switch (permission) {case READER:isAllowed = authorizationService.isReader(noteId, context.getUserAndRoles());allowed = authorizationService.getReaders(noteId);break;case WRITER:isAllowed = authorizationService.isWriter(noteId, context.getUserAndRoles());allowed = authorizationService.getWriters(noteId);break;case RUNNER:isAllowed = authorizationService.isRunner(noteId, context.getUserAndRoles());allowed = authorizationService.getRunners(noteId);break;case OWNER:isAllowed = authorizationService.isOwner(noteId, context.getUserAndRoles());allowed = authorizationService.getOwners(noteId);break;}if (isAllowed) {return true;} else {String errorMsg = "Insufficient privileges to " + permission + " note.\n" +"Allowed users or roles: " + allowed + "\n" + "But the user " +context.getAutheInfo().getUser() + " belongs to: " + context.getUserAndRoles();callback.onFailure(new ForbiddenException(errorMsg), context);return false;}}

2、zeppelin-shiro权限分析

zeppelin默认使用shiro.ini的方式来配置权限,它还支持从LDAP和其他Realm同步用户  zeppelin集成LDAP https://blog.csdn.net/EdwardWong_/article/details/115401467

我们在shiro中配置好的url,最终都会走org.apache.shiro.web.filter.authz.RolesAuthorizationFilter.isAccessAllowed()方法来处理,处理原理此处不细说,如果我们想使用Ranger来处理权限,此处是着手之处

package org.apache.shiro.web.filter.authz;import java.io.IOException;
import java.util.Set;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;// shiro 源码
public class RolesAuthorizationFilter extends AuthorizationFilter {public RolesAuthorizationFilter() {}public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {Subject subject = this.getSubject(request, response);String[] rolesArray = (String[])mappedValue;if (rolesArray != null && rolesArray.length != 0) {Set<String> roles = CollectionUtils.asSet(rolesArray);return subject.hasAllRoles(roles);} else {return true;}}
}

二、shiro权限原理分析及Ranger原理分析

1、shiro认证授权原理

// Todo...

2、Ranger认证授权原理

// Todo...

对于note粒度的权限,如果我们使用Ranger来鉴权,对zeppelin源码入侵性过大,后续zeppelin官方的升级适配和其他一些问题过于繁琐,所以再三思考过后决定先实现菜单权限层面的Ranger管控

三、自定义Ranger插件

官方给出了一些案例,阅读完后感觉一言难尽,了解到一些大概的流程,但是对于开发自定义插件帮助实在有限,于是一边借鉴其他官方Ranger插件的代码,一遍捋Ranger源码,最后终于开发成功。

ranger插件包层次如下

1、编写shiroService

pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>ranger</artifactId><groupId>org.apache.ranger</groupId><version>2.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>ranger-shiro-plugin</artifactId><dependencies><!-- Apache Shiro --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.7.0</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>1.7.0</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-config-core</artifactId><version>1.7.0</version></dependency><dependency><groupId>org.apache.ranger</groupId><artifactId>ranger-plugins-common</artifactId><version>2.0.0</version></dependency><dependency><groupId>org.apache.ranger</groupId><artifactId>ranger-plugins-audit</artifactId><version>2.0.0</version></dependency><dependency><groupId>org.apache.ranger</groupId><artifactId>credentialbuilder</artifactId><version>2.0.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>2.3</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals></execution></executions></plugin></plugins></build>
</project>

首先编写RangerService类,需要继承RangerBaseService类,并实现init()、validateConfig()、lookupResource方法。validateConfig()方法是对参数的验证方法,会对在RangerWeb界面上配置的zeppelin参数进行认证。lookResource方法是RangerWeb的一个自动补全参数方法,代码如下

package org.apache.ranger.services.shiro;import org.apache.ranger.plugin.client.BaseClient;
import org.apache.ranger.plugin.model.RangerService;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.service.RangerBaseService;
import org.apache.ranger.plugin.service.ResourceLookupContext;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author Edwards Wang* @version 2021/4/13 下午5:39* describe:*/
public class RangerServiceShiroTest extends RangerBaseService {@Overridepublic void init(RangerServiceDef serviceDef, RangerService service) {super.init(serviceDef, service);}@Overridepublic Map<String, Object> validateConfig() throws Exception {String errMes = "Failed,cannot connext to the zeppelin Service";String successMes = "Connection Success";Map<String, Object> map = new HashMap<>();if (!configs.containsKey("interpreterPage")){BaseClient.generateResponseDataMap(false,errMes,errMes,null,null,map);}else {BaseClient.generateResponseDataMap(true,successMes,successMes,null,null,map);}return map;}@Overridepublic List<String> lookupResource(ResourceLookupContext context) throws Exception {return null;}}

2、编写资源json文件

我们要对我们的插件有一个描述文件,文件要放在agents-common/src/main/resources/service-defs/路径下

首先是对插件的描述,需要有id、name、类路径、标签和描述

  "id":29,"name": "shiroTest2","implClass": "org.apache.ranger.services.shiro.RangerServiceShiroTest","label": "SHIRO Repository","description": "SHIRO Repository","resources":

然后是对我们插件要管控的资源的描述

{"itemId": 1,"name": "path","type": "path","level": 10,"parent": "","mandatory": true,"lookupSupported": true,"recursiveSupported": true,"excludesSupported": false,"matcher": "org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher","matcherOptions": { "wildCard":true, "ignoreCase":false },"validationRegEx":"","validationMessage": "","uiHint":"","label": "url","description": "url"}

然后是对权限的设置,这里只开启了一个权限get(此get和http请求无关,只是是否可以访问)

   {"itemId": 1,"name": "get","label": "get"}

完整的文件内容如下

{"id":29,"name": "shiroTest2","implClass": "org.apache.ranger.services.shiro.RangerServiceShiroTest","label": "SHIRO Repository","description": "SHIRO Repository","resources":[{"itemId": 1,"name": "path","type": "path","level": 10,"parent": "","mandatory": true,"lookupSupported": true,"recursiveSupported": true,"excludesSupported": false,"matcher": "org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher","matcherOptions": { "wildCard":true, "ignoreCase":false },"validationRegEx":"","validationMessage": "","uiHint":"","label": "url","description": "url"}],"accessTypes":[{"itemId": 1,"name": "get","label": "get"}],"configs":[{"itemId": 1,"name": "interpreterPage","type": "string","subType": "","mandatory": true,"validationRegEx":"","validationMessage": "","uiHint":"","label": "interpreterPage"}]
}

在完成service和资源文件后,需要执行命令将我们的插件加载进Ranger,命令如下:

curl -u admin:admin -X POST -H "Accept: application/json" -H "Content-Type: application/json" –d @ranger-servicedef-shiro.json 'http://localhost:6080/service/public/v2/api/servicedef'

然后需要重启RangerAdmin,接下来打开RangerWeb界面就能看到我们的插件了

3、编写Ranger授权类

我们的RangerShiroAuthorizer要继承shiro的org.apache.shiro.web.filter.authz.AuthorizationFilter类,并实现isAccessAllowed方法

package org.apache.ranger.authorization.shiro.authorizer;import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessResult;
import org.apache.ranger.plugin.service.RangerBasePlugin;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;/*** @author Edwards Wang* @version 2021/4/13 下午2:16* describe:*/
public class RangerShiroAuthorizer extends AuthorizationFilter {public RangerShiroAuthorizer() {}@Overridepublic boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {Subject subject = getSubject(request,response);// 获取用户String userName = (String) subject.getPrincipal();HttpServletRequest httpServletRequest = (HttpServletRequest) request;// 获取要拦截的urlStringBuffer url = httpServletRequest.getRequestURL();RangerAccessResourceImpl resource = new RangerAccessResourceImpl();resource.setValue("path",url.toString());RangerAccessRequestImpl rangerAccessRequest = new RangerAccessRequestImpl(resource,"get",userName,null);// 此处的名字要和json文件中定义的name插件名一致RangerBasePlugin rangerBasePlugin = new RangerBasePlugin("shiroTest2", "shiroTest2");rangerBasePlugin.setResultProcessor(new RangerDefaultAuditHandler());rangerBasePlugin.init();// 将权限交由Ranger来审核,返回boolean的值再交给shiroRangerAccessResult result = rangerBasePlugin.isAccessAllowed(rangerAccessRequest);return result != null && result.getIsAllowed();}
}

4、编写audit文件和security文件,我们要将这两个文件放在插件包的resource路径下:

首先是ranger-shiroTest2-audit.xml

<?xml version="1.0"?>
<!--Licensed to the Apache Software Foundation (ASF) under one or morecontributor license agreements.  See the NOTICE file distributed withthis work for additional information regarding copyright ownership.The ASF licenses this file to You under the Apache License, Version 2.0(the "License"); you may not use this file except in compliance withthe License.  You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License.
-->
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration xmlns:xi="http://www.w3.org/2001/XInclude"><!-- DB audit provider configuration --><property><name>xasecure.audit.destination.db</name><value>false</value></property><property><name>xasecure.audit.destination.db.jdbc.driver</name><value>com.mysql.jdbc.Driver</value></property><property><name>xasecure.audit.destination.db.jdbc.url</name><value>jdbc:mysql://localhost/ranger_audit</value></property><property><name>xasecure.audit.destination.db.password</name><value>rangerlogger</value></property><property><name>xasecure.audit.destination.db.user</name><value>rangerlogger</value></property><property><name>xasecure.audit.destination.db.batch.filespool.dir</name><value>/tmp/audit/db/spool</value></property><!-- HDFS audit provider configuration --><property><name>xasecure.audit.destination.hdfs</name><value>false</value></property><property><name>xasecure.audit.destination.hdfs.dir</name><value>hdfs://localhost:8020/ranger/audit</value></property><property><name>xasecure.audit.destination.hdfs.batch.filespool.dir</name><value>/tmp/audit/hdfs/spool</value></property><!-- Log4j audit provider configuration --><property><name>xasecure.audit.destination.log4j</name><value>true</value></property><property><name>xasecure.audit.destination.log4j.logger</name><value>ranger_audit_logger</value></property>
</configuration>

然后是ranger-shiroTest2-security.xml

有一个属性,需要特别注意。 这就是名为ranger.plugin.httpservice.service.name的属性。 此属性的值必须与您在Ranger UI中使用的服务名称相同。

<?xml version="1.0"?>
<!--Licensed to the Apache Software Foundation (ASF) under one or morecontributor license agreements.  See the NOTICE file distributed withthis work for additional information regarding copyright ownership.The ASF licenses this file to You under the Apache License, Version 2.0(the "License"); you may not use this file except in compliance withthe License.  You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License.
-->
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration xmlns:xi="http://www.w3.org/2001/XInclude"><property><name>ranger.plugin.shiroTest2.policy.rest.url</name><value>http://192.168.101.48:6080</value><description>URL to Ranger Admin</description></property><property><name>ranger.plugin.shiroTest2.service.name</name><value>MyService</value><description>Name of the Ranger service containing policies for this shiroTest2 instance</description></property><property><name>ranger.plugin.shiroTest2.policy.source.impl</name><value>org.apache.ranger.admin.client.RangerAdminRESTClient</value><description>Class to retrieve policies from the source</description></property><property><name>ranger.plugin.shiroTest2.policy.rest.ssl.config.file</name><value>ranger-policymgr-ssl.xml</value><description>Path to the file containing SSL details to contact Ranger Admin</description></property><property><name>ranger.plugin.shiroTest2.policy.pollIntervalMs</name><value>30000</value><description>How often to poll for changes in policies?</description></property><property><name>ranger.plugin.shiroTest2.policy.cache.dir</name><value>/tmp</value><description>Directory where Ranger policies are cached after successful retrieval from the source</description></property><property><name>ranger.plugin.shiroTest2.policy.rest.client.connection.timeoutMs</name><value>120000</value><description>RangerRestClient Connection Timeout in Milli Seconds</description></property><property><name>ranger.plugin.shiroTest2.policy.rest.client.read.timeoutMs</name><value>30000</value><description>RangerRestClient read Timeout in Milli Seconds</description></property>
</configuration>

然后打包。接下来开始写shiro拦截器部分

四、自定义Shiro拦截器(RangerFilter)

在zeppelin的zeppelin-server/src/main/java/org/apache/zeppelin下新建一个filter包,在filter包下新建一个shiro拦截器:RangerFilter,继承org.apache.shiro.web.filter.authz.AuthorizationFilter方法,实现isAccessAllowed方法,在方法里直接调用我们ranger插件包内的isAccessAllowed方法

package org.apache.zeppelin.filter;import org.apache.ranger.authorization.shiro.authorizer.RangerShiroAuthorizer;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;/*** @author Edwards Wang* @version 2021/4/20 下午2:30* describe:*/
public class RangerFilter extends AuthorizationFilter {@Overrideprotected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {return new RangerShiroAuthorizer().isAccessAllowed(request,response,mappedValue);}
}

然后修改shiro.ini文件,在[main]模块下新增条目

[main]
rangerFilter = org.apache.zeppelin.filter.RangerFilter

在[url]模块下修改条目,此处只以解释器页面为例

[urls]
/api/version = anon
/api/cluster/address = anon
/api/interpreter/setting/restart/** = authc
/api/interpreter/** = authc, rangerFilter

完整的shiro.ini文件如下

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#[users]
# List of users with their password allowed to access Zeppelin.
# To use a different strategy (LDAP / Database / ...) check the shiro doc at http://shiro.apache.org/configuration.html#Configuration-INISections
# To enable admin user, uncomment the following line and set an appropriate password.
#admin = password1, admin
user1 = password2, role1, role2
user2 = password3, role3
user3 = password4, role2# Sample LDAP configuration, for user Authentication, currently tested for single Realm
[main]
### A sample for configuring Active Directory Realm
#activeDirectoryRealm = org.apache.zeppelin.realm.ActiveDirectoryGroupRealm
#activeDirectoryRealm.systemUsername = userNameA#use either systemPassword or hadoopSecurityCredentialPath, more details in http://zeppelin.apache.org/docs/latest/security/shiroauthentication.html
#activeDirectoryRealm.systemPassword = passwordA
#activeDirectoryRealm.hadoopSecurityCredentialPath = jceks://file/user/zeppelin/zeppelin.jceks
#activeDirectoryRealm.searchBase = CN=Users,DC=SOME_GROUP,DC=COMPANY,DC=COM
#activeDirectoryRealm.url = ldap://ldap.test.com:389
#activeDirectoryRealm.groupRolesMap = "CN=admin,OU=groups,DC=SOME_GROUP,DC=COMPANY,DC=COM":"admin","CN=finance,OU=groups,DC=SOME_GROUP,DC=COMPANY,DC=COM":"finance","CN=hr,OU=groups,DC=SOME_GROUP,DC=COMPANY,DC=COM":"hr"
#activeDirectoryRealm.authorizationCachingEnabled = false### A sample for configuring LDAP Directory Realm
#ldapRealm = org.apache.zeppelin.realm.LdapGroupRealm
## search base for ldap groups (only relevant for LdapGroupRealm):
#ldapRealm.contextFactory.environment[ldap.searchBase] = dc=COMPANY,dc=COM
#ldapRealm.contextFactory.url = ldap://ldap.test.com:389
#ldapRealm.userDnTemplate = uid={0},ou=Users,dc=COMPANY,dc=COM
#ldapRealm.contextFactory.authenticationMechanism = simple### A sample PAM configuration
#pamRealm=org.apache.zeppelin.realm.PamRealm
#pamRealm.service=sshd### A sample for configuring ZeppelinHub Realm
#zeppelinHubRealm = org.apache.zeppelin.realm.ZeppelinHubRealm
## Url of ZeppelinHub
#zeppelinHubRealm.zeppelinhubUrl = https://www.zeppelinhub.com
#securityManager.realms = $zeppelinHubRealm## A same for configuring Knox SSO Realm
#knoxJwtRealm = org.apache.zeppelin.realm.jwt.KnoxJwtRealm
#knoxJwtRealm.providerUrl = https://domain.example.com/
#knoxJwtRealm.login = gateway/knoxsso/knoxauth/login.html
#knoxJwtRealm.logout = gateway/knoxssout/api/v1/webssout
#knoxJwtRealm.logoutAPI = true
#knoxJwtRealm.redirectParam = originalUrl
#knoxJwtRealm.cookieName = hadoop-jwt
#knoxJwtRealm.publicKeyPath = /etc/zeppelin/conf/knox-sso.pem
#
#knoxJwtRealm.groupPrincipalMapping = group.principal.mapping
#knoxJwtRealm.principalMapping = principal.mapping
#authc = org.apache.zeppelin.realm.jwt.KnoxAuthenticationFilter
rangerFilter = org.apache.zeppelin.filter.RangerFiltersessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager### If caching of user is required then uncomment below lines
#cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
#securityManager.cacheManager = $cacheManager### Enables 'HttpOnly' flag in Zeppelin cookies
cookie = org.apache.shiro.web.servlet.SimpleCookie
cookie.name = JSESSIONID
cookie.httpOnly = true
### Uncomment the below line only when Zeppelin is running over HTTPS
#cookie.secure = true
sessionManager.sessionIdCookie = $cookiesecurityManager.sessionManager = $sessionManager
# 86,400,000 milliseconds = 24 hour
securityManager.sessionManager.globalSessionTimeout = 86400000
shiro.loginUrl = /api/login[roles]
role1 = *
role2 = *
role3 = *
admin = *[urls]
# This section is used for url-based security. For details see the shiro.ini documentation.
#
# You can secure interpreter, configuration and credential information by urls.
# Comment or uncomment the below urls that you want to hide:
# anon means the access is anonymous.
# authc means form based auth Security.
#
# IMPORTANT: Order matters: URL path expressions are evaluated against an incoming request
# in the order they are defined and the FIRST MATCH WINS.
#
# To allow anonymous access to all but the stated urls,
# uncomment the line second last line (/** = anon) and comment the last line (/** = authc)
#
/api/version = anon
/api/cluster/address = anon
# Allow all authenticated users to restart interpreters on a notebook page.
# Comment out the following line if you would like to authorize only admin users to restart interpreters.
/api/interpreter/setting/restart/** = authc
/api/interpreter/** = authc, rangerFilter
/api/notebook-repositories/** = authc, roles[admin]
/api/configurations/** = authc, roles[admin]
/api/credential/** = authc, roles[admin]
/api/admin/** = authc, roles[admin]
#/** = anon
/** = authc

修改完毕,将ranger和ranger插件的包放到lib路径下重启zeppelin

五、测试

首先打开zeppelin的界面,使用默认的user1用户登录,访问interpreter界面,会发现报错说没有权限

然后我们进入RangerWeb界面配置权限,首先配置插件

然后配置策略,将url和用户角色权限加上

点击add或save,然后重新回到zeppelin界面,这回就可以正常访问解释器页面了

大功告成!!

有任何问题可以评论留言,开发过程中有一些坑,大家遇到我踩过的可以帮大家解答一下

自定义Ranger插件 Zeppelin集成Ranger方案 (非LDAP模式)相关推荐

  1. apache ranger_Apache Ranger插件的美丽简洁

    apache ranger 如果您在这里,您已经知道什么是Apache Ranger . 这是在Hadoop框架中管理安全性的最流行(即使不是唯一)的方法. 它与Active Directory,Ke ...

  2. Apache Ranger插件的美丽简洁

    如果您在这里,您已经知道什么是Apache Ranger . 它是管理Hadoop框架中安全性的最流行(即使不是唯一)的方法. 它与Active Directory,Kerberos和其他各种身份验证 ...

  3. AWS EMR内置Ranger插件使用的IAM Role及其设计策略

    AWS EMR提供三种内置的Ranger插件,分别是:S3(EMRFS),Spark,Hive,如果要启用这些插件,需要创建三个特定的IAM Role,以便相关组件能获得适当的权限.对这三种Role的 ...

  4. Ldap集成Ranger应用服务

    1.Ldap配置信息 gitlab_rails['ldap_servers'] = YAML.load <<-'EOS' main: # 'main' is the GitLab 'pro ...

  5. Android如何自定义Gradle插件

    Android-如何自定义gradle插件 自定义gradle插件可以实现定制自己的构建流程,以达到复用目的: ##1. 自定义插件方式 自定义插件有三种方式 添加脚步 在你的app项目的build. ...

  6. Springboot集成datax方案小记

    Springboot集成datax方案小记 datax源码下载与编译 datax job config Springboot工程 pom.xml 主运行程序 遇到的个掰倒霉问题 另 datax源码下载 ...

  7. 如何自定义sonar插件并学会使用

    1.接触sonar已经有点时间了,sonar集成了findbugs,pmd,checkstyle各种静态代码检查工具的功能,并且可以将各种扫描结果组合成一张张漂亮的报告,功能很是强大. 2.对于开发人 ...

  8. typecho图标_Typecho微信自定义分享插件WeChatShare 自定义标题描述小图标

    前言 张小龙带领微信走进了大众的生活,在十亿用户的生活里扎根.于是我们不管是阅读.聊天.看视频,基本上都离不开微信.好东西分享给用户,第一时间想到的肯定是微信. 很久以前,一个网页分享到微信聊天,系统 ...

  9. skywalking自定义增强插件apm-customize-enhance-plugin

    skywalking自定义增强插件apm-customize-enhance-plugin skywalking支持自定义增强插件,可在指定类中增强方法,但是需要在xml中将所有需要增强的方法都列出来 ...

最新文章

  1. 算法训练 最大的算式
  2. Sql查询一个列对应多个列
  3. IIC总线上挂载多个从机的程序实现
  4. VC6.0 预编译(转)
  5. ​NVIDIA针对数据不充分数据集进行生成改进,大幅提高CIFAR-10数据生成
  6. linux读conf文件格式,CONF 文件扩展名: 它是什么以及如何打开它?
  7. Java8排序–性能陷阱
  8. 全栈工程师可以分为哪几类?
  9. many to many mysql_mysql “Too many connections” 解决办法
  10. php+foreach+传值传值,php foreach 传值还是传引用
  11. ElementUI腾讯云开发者开发指南
  12. NOIP模拟 位运算(trie树+按位贪心)
  13. python学英语库_交流学英语的经验-js焦点图怎么写-WinFrom控件库|.net开源控件库|HZHControls官网...
  14. ORACLE 字符集修改,ZHS16GBK转US7ASCII
  15. 【Python成长之路】快速理解复制、浅拷贝、深拷贝
  16. Java生成sitemap网站地图
  17. 【Python】解决CNN中训练权重参数不匹配size mismatch for fc.weight,size mismatch for fc.bias
  18. 【技术点】数据结构--B树系列(四)
  19. SHA224和SHA256哈希算法原理及实现(附源码)
  20. html表单的基本结构

热门文章

  1. 图像类型的转换(matlab)
  2. 机器学习5-线性回归算法的代码实现
  3. 【网易区块链阅读APP易头条上线】
  4. FlaskFul返回中文被转义unicode解决方法
  5. c#开发安卓之一——加速器开启
  6. php实现进制转换计算器,利用php怎么实现一个进制转换功能
  7. BES2300x笔记----TWS组对与蓝牙配对
  8. Ubuntu配置中文输入法
  9. linux shutdown 定时关机,Linux系统Shutdown命令定时关机详解
  10. “讨好型人格”在社会中为什么总是吃亏