How to configure roles based on groups from HadoopGroupProvider in Zeppelin, using Knox to provide SAML-based SSO? - apache-zeppelin

I am trying to implement Role Base Access Controls on Zeppelin, using Knox to authenticate against an external IdP, and to perform group lookups from an LDAP instance once a user has been successfully authenticated.
I am currently able to login to Zeppelin, and the HadoopGroupProvider is looking up the user's groups as expected, but the authenticated user is not mapped to any roles, and is therefore unable to create Notebooks, or use any interpreters.
My configuration for Knox is shown below:
<?xml version="1.0" encoding="utf-8"?>
<topology>
<gateway>
<provider>
<role>federation</role>
<name>pac4j</name>
<enabled>true</enabled>
<param>
<name>pac4j.callbackUrl</name>
<value>https://knox.example.com/gateway/knoxsso/api/v1/websso</value>
</param>
<param>
<name>clientName</name>
<value>SAML2Client</value>
</param>
<param>
<name>saml.keystorePath</name>
<value>/opt/knox-1.3.0/data/security/keystores/gateway.jks</value>
</param>
<param>
<name>saml.keystorePassword</name>
<value>password</value>
</param>
<param>
<name>saml.privateKeyPassword</name>
<value>password</value>
</param>
<param>
<name>saml.identityProviderMetadataPath</name>
<value>/etc/sso/idp.xml</value>
</param>
<param>
<name>saml.maximumAuthenticationLifetime</name>
<value>100000</value>
</param>
<param>
<name>saml.serviceProviderEntityId</name>
<value>https://knox.example.com/gateway/knoxsso/api/v1/websso?pac4jCallback=true&client_name=SAML2Client</value>
</param>
<param>
<name>saml.serviceProviderMetadataPath</name>
<value>/etc/sso/sp.xml</value>
</param>
<param>
<name>pac4j.id_attribute</name>
<value>username</value>
</param>
</provider>
<provider>
<role>identity-assertion</role>
<name>HadoopGroupProvider</name>
<enabled>true</enabled>
<param>
<name>hadoop.security.group.mapping</name>
<value>org.apache.hadoop.security.LdapGroupsMapping</value>
</param>
<param>
<name>hadoop.security.group.mapping.ldap.bind.user</name>
<value>cn=loginuser,ou=example,ou=example,dc=example,dc=example,dc=example,dc=com</value>
</param>
<param>
<name>hadoop.security.group.mapping.ldap.bind.password</name>
<value>password</value>
</param>
<param>
<name>hadoop.security.group.mapping.ldap.url</name>
<value>ldap://example.ldap.com:389</value>
</param>
<param>
<name>hadoop.security.group.mapping.ldap.base</name>
<value>ou=example,dc=example,dc=example,dc=example,dc=com</value>
</param>
<param>
<name>hadoop.security.group.mapping.ldap.search.filter.user</name>
<value>(&(objectClass=user)(|(sAMAccountName={0})(mailNickname={0})))</value>
</param>
<param>
<name>hadoop.security.group.mapping.ldap.search.filter.group</name>
<value>(&(cn=group*)(objectclass=Group))</value>
</param>
<param>
<name>hadoop.security.group.mapping.ldap.search.attr.member</name>
<value>member</value>
</param>
<param>
<name>hadoop.security.group.mapping.ldap.search.attr.group.name</name>
<value>cn</value>
</param>
</provider>
</gateway>
<service>
<role>KNOXSSO</role>
<param>
<name>knoxsso.cookie.secure.only</name>
<value>true</value>
</param>
<param>
<name>knoxsso.token.ttl</name>
<value>100000</value>
</param>
<param>
<name>knoxsso.redirect.whitelist.regex</name>
<value>.*</value>
</param>
<param>
<name>knoxsso.token.ttl</name>
<value>-1</value>
</param>
</service>
</topology>
This is my shiro.ini configuration for Zeppelin:
[main]
knoxJwtRealm = org.apache.zeppelin.realm.jwt.KnoxJwtRealm
knoxJwtRealm.providerUrl = https://knox.example.com/
knoxJwtRealm.login = gateway/knoxsso/api/v1/websso
knoxJwtRealm.publicKeyPath = /etc/pki/tls/certs/knox.example.com.pem
knoxJwtRealm.logoutAPI = false
knoxJwtRealm.logout = gateway/knoxsso/api/v1/webssout
knoxJwtRealm.cookieName = hadoop-jwt
knoxJwtRealm.redirectParam = originalUrl
knoxJwtRealm.groupPrincipalMapping = group.principal.mapping
knoxJwtRealm.principalMapping = principal.mapping
authc = org.apache.zeppelin.realm.jwt.KnoxAuthenticationFilter
securityManager.realms = $knoxJwtRealm
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
cookie = org.apache.shiro.web.servlet.SimpleCookie
cookie.name = JSESSIONID
cookie.httpOnly = true
sessionManager.sessionIdCookie = $cookie
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.globalSessionTimeout = 86400000
shiro.loginUrl = /api/login
[roles]
admin_role = *
user_role = *
[urls]
/api/version = anon
/** = authc
I am confident that the HadoopGroupProvider is connecting to my LDAP instance and successfully looking up my groups, due to the gateway-audit.log:
19/10/07 15:33:00 ||6348f279-0ed2-445b-8a73-b76a8fcb985a|audit|1.2.3.4|KNOXSSO|USER1|||identity-mapping|principal|USER1|success|Groups: [Group1, Group2, Group3]
My questions are:
How do I map these groups to roles in Zeppelin?
Is there an equivalent to the org.apache.zeppelin.realm.LdapRealm's rolesByGroup configuration for the KnoxJwtRealm?
Any help is greatly appreciated, thanks in advance!

You need to install hadoop binaries and configure Hadoop Group Mapping.
And get Zeppelin rely on this configuration by providing environment variables in zeppelin-env.sh:
USE_HADOOP=True
HADOOP_CONF_DIR=<PATH_TO_HADOOP_CONFIGURATION_FILES>
You either need to add $HADOOP_HOME/bin to your OS $PATH environment variable. So Zeppelin could run hadoop command to map users and groups.
Setup specific group access permissions by writing URL-based rules under url section, such as:
[urls]
/api/configurations/** = authc, roles[<YOUR_LDAP_GROUP>]
More info:
Hadoop integration
Zeppelin KnoxSSO

The group lookup in the HadoopGroupProvider within the Knox topology looks correct and you would be able to use those groups for service level authorization for protecting access to the services being proxied by that topology.
However, those groups do not get propagated to the backend service from the gateway. Zeppelin needs to be configured to do its own group lookup and role mapping. I'm not familiar with the Zeppelin config for that unfortunately.
The following may prove helpful though: https://zeppelin.apache.org/docs/0.8.0/setup/security/shiro_authentication.html#groups-and-permissions-optional

Related

WildFly 10.1 Failed to create journal-datasource to store message

I'm using an old version of WildFly (10.1) which uses the ActiveMQ Artemis that comes with it, and I was trying to switch the store method from a store in the file system to store in the database (and I know that the ActiveMQ Artemis default way to store the is better).
So I'm using this configuration for ActiveMQ Artemis:
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
<server name="default">
<security-setting name="#">
<role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
</security-setting>
<address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10"/>
<http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
<http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
<param name="batch-delay" value="50"/>
</http-connector>
<in-vm-connector name="in-vm" server-id="0"/>
<http-acceptor name="http-acceptor" http-listener="default"/>
<http-acceptor name="http-acceptor-throughput" http-listener="default">
<param name="batch-delay" value="50"/>
<param name="direct-deliver" value="false"/>
</http-acceptor>
<in-vm-acceptor name="in-vm" server-id="0"/>
<jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
<jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
<connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
<connection-factory name="RemoteConnectionFactory" connectors="http-connector" entries="java:jboss/exported/jms/RemoteConnectionFactory"/>
<pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
</server>
</subsystem>
and than using jboss-cli.bat (I'm using Windows), I run this command:
/subsystem=messaging-activemq/server=vmvanz:write-attribute(name=journal-datasource, value=ExampleDS)
And I get this error:
{
"outcome" => "failed",
"failure-description" => "WFLYCTL0201: Unknown attribute 'journal-datasource'",
"rolled-back" => true
}
I try the same command in WildFly 14 and work. I read the documentation from 10.1 and it show the same command line.
Does someone knows if this is a problem from this version or know some other way to configure?
WildFly 10.1 doesn't support the journal-datasource attribute. It ships with version 1.0 of the ActiveMQ messaging configuration schema. This is specified in your configuration here:
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
The journal-datasource attribute wasn't available until version 2.0 of the ActiveMQ messaging configuration schema which first appeared in WildFly 11.
Also, the documentation you linked is for WildFly 13. This is visible in the URL:
https://docs.wildfly.org/13/Admin_Guide.html#Messaging_JDBC_Store_for_Messaging_Journal

How can I remove the hard coding of the web service address from .ClientConfig files

I have 5 SilverLight projects in my ASP .NET MVC 4 application. For each of these projects, there is a web service which passes data to and from the silverlight control.
When we deploy the application on the client's server, we update the .ClientConfig file of each SilverLight project by changing the address of the web service.
That is we change -
<endpoint address="http://localhost:52213/SchemeReimbursementMasterService.asmx"
binding="basicHttpBinding" bindingConfiguration="SchemeReimbursementMasterServiceSoap"
contract="SchemeServiceReference.SchemeReimbursementMasterServiceSoap"
name="SchemeReimbursementMasterServiceSoap" />
to -
<endpoint address="http://192.168.5.48/SCHEME/SchemeReimbursementMasterService.asmx"
binding="basicHttpBinding" bindingConfiguration="SchemeReimbursementMasterServiceSoap"
contract="SchemeServiceReference.SchemeReimbursementMasterServiceSoap"
name="SchemeReimbursementMasterServiceSoap" />
Then we build it and publish the application.
So, in future, if the address changes, we would have to change it in all the five .ClientConfig files and build/publish it again. Is there any way we can remove this hardcoding so that it figures out the base part of the url (i.e: http://192.168.5.48/SCHEME/) on its own.
In my application's web.config, I added keys for the service names.
<appSettings>
<add key="ReviewUrl" value="ReviewClaimsService.asmx"/>
<add key="ReimbursementUrl" value="SchemeReimbursementMasterService.asmx"/>
<add key="DiscountUrl" value="DiscountMasterSchemeService.asmx"/>
</appSettings>
In the controller, I created the URL using the HttpContext and the service name from web.config and passed it to the view.
var baseUrl = "http://" + HttpContext.Request.Headers["Host"];
var applicationPath = HttpContext.Request.ApplicationPath;
if (applicationPath == "/")
baseUrl = baseUrl + "/";
var url = baseUrl + ConfigurationManager.AppSettings["ReimbursementUrl"];
In the View, I passed this URL to the silverlight control using InitParams.
<object id="TownsGrid" data="data:application/x-silverlight-2," type="application/x-silverlight-2">
<param name="InitParams" value="ControlName=TownDataGrid,ServiceUrl=#Model.ServiceUrl" />
<param name="source" value="#Url.Content("~/ClientBin/SilverlightApplication.xap")"/>
</object>
In the Application_Startup method of the silverlight project, I passed the URL on to the SilverLight control.
private void Application_Startup(object sender, StartupEventArgs e)
{
var url = e.InitParams["ServiceUrl"];
this.RootVisual = new SilverlightApplication.TownDataGrid(url);
}
And finally, in the silverlight control, I assign the url to the endpoint.
public TownDataGrid(string serviceUrl)
{
InitializeComponent();
EndpointAddress endpoint = new EndpointAddress(serviceUrl);
BasicHttpBinding binding = new BasicHttpBinding();
client = new SchemeReimbursementMasterServiceSoapClient(binding,endpoint);
}

jboss gatein merge.js gives errors

I am using jboss gatein 3.2 for my web application. In the gatein-resource.xml, i have upgraded from ext-js 3.2 to 3.4. which gives me java script error in the firebug console and all the ext-js components and menu of the gatein portlets are all also not loaded. This happens in the production mode only but works fine in the development mode. What could be wrong(ext-js 3.2 works fine in both development mode as well as production mode)
TypeError: eXo.portal.UIPortal is undefined
the bellow is my gatein resource.xml
<?xml version="1.0" encoding="UTF-8"?>
<gatein-resources
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_resources_1_1 http://www.gatein.org/xml/ns/gatein_resources_1_1"
xmlns="http://www.gatein.org/xml/ns/gatein_resources_1_1">
<javascript>
<param>
<js-module>extbaseJS</js-module>
<js-path>/javascript/lib/ext-2.1/adapter/ext/ext-base.js</js-path>
<js-priority>1</js-priority>
</param>
<param>
<js-module>extallJS</js-module>
<js-path>/javascript/lib/ext-2.1/ext-all.js</js-path>
<js-priority>2</js-priority>
</param>
<param>
<js-module>extcommonsJS</js-module>
<js-path>/javascript/commons/extCommons.js</js-path>
<js-priority>3</js-priority>
</param>
<param>
<js-module>dateJS</js-module>
<js-path>/javascript/date/date.js</js-path>
<js-priority>2</js-priority>
</param>
<param>
<js-module>extcalendarJS</js-module>
<js-path>/javascript/commons/extcalendar.js</js-path>
<js-priority>2</js-priority>
</param>
<param>
<js-module>cismstableJS</js-module>
<js-path>/javascript/tables/cismstable.js</js-path>
<js-priority>1</js-priority>
</param>
<param>
<js-module>viewJS</js-module>
<js-path>/javascript/tables/view.js</js-path>
<js-priority>1</js-priority>
</param>
<param>
<js-module>validationJS</js-module>
<js-path>/javascript/commons/validation.js</js-path>
<js-priority>1</js-priority>
</param>
<param>
<js-module>commonslookupJS</js-module>
<js-path>/javascript/commons/commons-lookup.js</js-path>
<js-priority>1</js-priority>
</param>
<!-- <param>
<js-module>fusionChartsJS</js-module>
<js-path>/javascript/charts/FusionCharts.js</js-path>
<js-priority>1</js-priority>
</param>
<param>
<js-module>securityCharts</js-module>
<js-path>/javascript/charts/securityChart.js</js-path>
<js-priority>1</js-priority>
</param> -->
<param>
<js-module>DwrProxy</js-module>
<js-path>/javascript/lib/DwrProxy.js</js-path>
<js-priority>4</js-priority>
</param>
<param>
<js-module>dynamicColumn</js-module>
<js-path>/javascript/commons/dynamicColumn.js</js-path>
<js-priority>5</js-priority>
</param>
<param>
<js-module>dateUtils</js-module>
<js-path>/javascript/date/dateUtils.js</js-path>
<js-priority>2</js-priority>
</param>
<param>
<js-module>extObjectPopup</js-module>
<js-path>/javascript/extWidgets/extObjectPopup/extObjectPopup.js</js-path>
<js-priority>5</js-priority>
</param>
<param>
<js-module>Spotlight</js-module>
<js-path>/javascript/lib/ext-2.1/Spotlight.js</js-path>
<js-priority>5</js-priority>
</param>
<param>
<js-module>ExtColumnHeader</js-module>
<js-path>/javascript/lib/ext-2.1/ColumnHeaderGroup.js</js-path>
<js-priority>5</js-priority>
</param>
<param>
<js-module>toolTreeTrends</js-module>
<js-path>/javascript/dtree/toolTreeTrends.js</js-path>
<js-priority>6</js-priority>
</param>
<param>
<js-module>toolTreeThreat</js-module>
<js-path>/javascript/dtree/toolTree.js</js-path>
<js-priority>4</js-priority>
</param>
<param>
<js-module>dynamicColumn</js-module>
<js-path>/javascript/commons/dropdownGrid.js</js-path>
<js-priority>6</js-priority>
</param>
<param>
<js-module>rgraph</js-module>
<js-path>/javascript/charts/RGraph.common.core.js</js-path>
<js-priority>6</js-priority>
</param>
<param><!--RIMS_05.05_M1_BUG_35 -->
<js-module>BarChart</js-module>
<js-path>/javascript/charts/BarChart.js</js-path>
<js-priority>1</js-priority>
</param>
<param><!--RIMS_05.05_M1_BUG_36 -->
<js-module>LineChart</js-module>
<js-path>/javascript/charts/LineChart.js</js-path>
<js-priority>1</js-priority>
</param>
</javascript>
</gatein-resources>
On the recent version of GateIn (GateIn 3.6) they changed the javascript importing syntax in gatein-resources.xml and resource compression mechanism . You can find more about that from This Link
You need to update your gatein-resources.xml in order to be compliant with the new syntax:
<scripts>
<name>extJS</name>
<script>
<path>/javascript/lib/ext-2.1/adapter/ext/ext-base.js</path>
</script>
<script>
<path>/javascript/lib/ext-2.1/ext-all.js</path>
</script>
.....
</scripts>
GateIn 3.6 provides now on demand, flexible and parallel loading of JavaScript resources. So you can also use AMD(Asynchronous module definition).
For a shared scope (Gatein support portal, portlet and shared scope), you can define your javascript modules like this:
<module>
<name>extbase</name>
<script>
<path>/javascript/lib/ext-2.1/adapter/ext/ext-base.js</path>
</script>
<depends>
<module>base</module>
</depends>
</module>
<module>
<name>extall</name>
<script>
<path>/javascript/lib/ext-2.1/ext-all.js</path>
</script>
<depends>
<module>extbase</module>
</depends>
</module>
....
You can find more information about Javascript development in GateIn here :
https://docs.jboss.org/author/display/GTNPORTAL35/JavaScript+Development

Need some ideas on how to generate combo boxes dynamically (wpf)

To start off, I have this XML file that contains recursive parent-child elements. Here is how the XML looks:
<VARS>
<VAR>
<id>var_starting_point</id>
<name>Starting Point</name>
<values>
<value>
<id>http://Environment1URL.com</id>
<name>Enviornment 1</name>
<sub_vars>
<VAR>
<id>var_env1_data</id>
<name>Env1 Data</name>
<values>
<value>
<name>Data1</name>
<sub_var>
<VAR>
<id>var_db</id>
<name>DB</name>
<values>
<values>place-holder 1</values>
</values>
</VAR>
</sub_var>
</value>
<value>
<name>Data2</name>
<sub_var>
<VAR>
<id>var_db</id>
<name>DB</name>
<values>
<values>place-holder 2</values>
</values>
</VAR>
</sub_var>
</value>
</values>
</VAR>
</sub_vars>
</value>
<value>
<id>http://Environment2URL.com</id>
<name>Enviornment 2</name>
<sub_vars>
<VAR>
<id>var_env2_data</id>
<name>Env2 Data</name>
<values>
<value>
<name>Data1</name>
<sub_var>
<VAR>
<id>var_db</id>
<name>DB</name>
<values>
<values>place-holder 1</values>
</values>
</VAR>
</sub_var>
</value>
<value>
<name>Data2</name>
<sub_var>
<VAR>
<id>var_db</id>
<name>DB</name>
<values>
<values>place-holder 2</values>
</values>
</VAR>
</sub_var>
</value>
</values>
</VAR>
</sub_vars>
</value>
</values>
</VAR>
<VAR>
<id>var_version_data1</id>
<name>Data1 Version</name>
<values>
<value>
<name>1.1.1</name>
</value>
</values>
</VAR>
<VAR>
<id>var_version_data2</id>
<name>Data2 Version</name>
<values>
<value>
<name>2.2.2</name>
</value>
</values>
</VAR>
</VARS>
I have a VARS element which contain 1 or more VAR element which has an id, name and
values array which contain 1 or more value elements.
The sub_var and id elements of the value element is optional, the name
element is not. The sub_var contains the exact same stuff as VARS
and so on.
Now I want to generate child combo boxes based on what was choosen in the
parent comboBox.
For example, if the user chooses "Enviornment 1" from the
Starting Point comboBox, than an Env1 Data combo box should spawn with
the Env1 values. Then if the user chooses "Data1", then the DB combo box
should be populated with "place-holder 1".
I've been working on this for hours and I'm not getting anywhere. I was able to get
1 layer working non recursivley, however multiple nested elements have been giving me a headache.
The way I do it now is, save the selected item to a temp variable, then on my selection changed event handler I clear my stack panel and recreate all the combo boxes based on what was selected last. However this does not seem to be working properly with multiple nested elements.
I'm just looking for ideas and how you would approach this problem.
First, I would deserialize your structure into a class that looked like this:
class XmlVar
{
public List<XmlVar> Children { get; set; }
public string ID { get; set; }
public string Name { get; set; }
}
Once you did this, you can add a method to XmlVar to create your ComboBox for that node. Something like this:
public ComboBox MakeNodeCombo()
{
ComboBox retval = new ComboBox();
if (Children != null)
{
foreach (XmlVar child in Children)
{
ComboBoxItem nextItem = new ComboBoxItem;
nextItem.Content = Name;
nextItem.Tag = child; // So we have an easy time choosing the child
retval.Add(nextItem);
}
}
return retval;
}
When you get a SelectedItem event, get the corresponding ComboBoxItem. It's Content is the Name, and its Tag is the child XmlVar node that you now want to target.
I would probably deserialize this to proper C# classes, that way you can define HierarchicalDataTemplates which can be implicitly applied via the DataType property. Then you should just need to create one such template and a root ContentControl or ItemsControl to which you can bind your root and it should generate everything as needed.

How do I prevent SimpleSecurityManager being used in JackRabbit?

How I stop Jackrabbit using SimpleSecurityManager?
I'm trying to call session.getUserManager() but I get a repository exception as SimpleSecurityManager.getUserManager() explicity throws it.
<Security appName="Jackrabbit">
<SecurityManager class="org.apache.jackrabbit.core.DefaultSecurityManager" workspaceName="security">
</SecurityManager>
<AccessManager class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
<!-- <param name="config" value="${rep.home}/access.xml"/> -->
</AccessManager>
<LoginModule class="org.apache.jackrabbit.core.security.authentication.DefaultLoginModule">
<param name="anonymousId" value="anonymous"/>
<param name="adminId" value="admin"/>
</LoginModule>
</Security>
Rest of code for those that will ask...
Repository repository = new TransientRepository();
Session jackrabbitSession = repository.login(credentials);
UserManager userManager = session.getUserManager();
The user manager is a Jackrabbit extension. It's not a part of the JCR. So, you need to use a JackrabbitSession, not just a Session. Here's a link to the wiki:
http://wiki.apache.org/jackrabbit/UserManagement

Resources