Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
atlas
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
dataplatform
atlas
Commits
403c04b3
Commit
403c04b3
authored
Mar 20, 2015
by
Jon Maron
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
BUG-32834 servlet context listener supporting simple and kerberos logins
parent
12beefbb
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
343 additions
and
0 deletions
+343
-0
pom.xml
webapp/pom.xml
+27
-0
LoginListener.java
...g/apache/hadoop/metadata/web/listeners/LoginListener.java
+139
-0
web.xml
webapp/src/main/webapp/WEB-INF/web.xml
+3
-0
LoginListenerIT.java
...apache/hadoop/metadata/web/listeners/LoginListenerIT.java
+174
-0
No files found.
webapp/pom.xml
View file @
403c04b3
...
@@ -156,6 +156,25 @@
...
@@ -156,6 +156,25 @@
<groupId>
org.mortbay.jetty
</groupId>
<groupId>
org.mortbay.jetty
</groupId>
<artifactId>
jsp-2.1
</artifactId>
<artifactId>
jsp-2.1
</artifactId>
</dependency>
</dependency>
<dependency>
<groupId>
org.apache.hadoop
</groupId>
<artifactId>
hadoop-client
</artifactId>
<version>
${hadoop.version}
</version>
</dependency>
<dependency>
<groupId>
org.apache.hadoop
</groupId>
<artifactId>
hadoop-minikdc
</artifactId>
<version>
${hadoop.version}
</version>
</dependency>
<dependency>
<groupId>
commons-io
</groupId>
<artifactId>
commons-io
</artifactId>
<version>
2.4
</version>
</dependency>
</dependencies>
</dependencies>
<build>
<build>
...
@@ -339,6 +358,14 @@
...
@@ -339,6 +358,14 @@
</execution>
</execution>
</executions>
</executions>
</plugin>
</plugin>
<plugin>
<groupId>
org.apache.felix
</groupId>
<artifactId>
maven-bundle-plugin
</artifactId>
<inherited>
true
</inherited>
<extensions>
true
</extensions>
</plugin>
</plugins>
</plugins>
</build>
</build>
</project>
</project>
webapp/src/main/java/org/apache/hadoop/metadata/web/listeners/LoginListener.java
0 → 100644
View file @
403c04b3
/*
* 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.
*/
package
org
.
apache
.
hadoop
.
metadata
.
web
.
listeners
;
import
org.apache.commons.configuration.ConfigurationException
;
import
org.apache.commons.configuration.PropertiesConfiguration
;
import
org.apache.hadoop.conf.Configuration
;
import
org.apache.hadoop.security.SecurityUtil
;
import
org.apache.hadoop.security.UserGroupInformation
;
import
org.apache.hadoop.util.Shell
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
javax.servlet.ServletContextEvent
;
import
javax.servlet.ServletContextListener
;
import
java.io.IOException
;
import
java.net.InetAddress
;
/**
* A listener capable of performing a simple or kerberos login.
*/
public
class
LoginListener
implements
ServletContextListener
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
LoginListener
.
class
);
public
static
final
String
AUTHENTICATION_METHOD
=
"authentication.method"
;
public
static
final
String
AUTHENTICATION_PRINCIPAL
=
"authentication.principal"
;
public
static
final
String
AUTHENTICATION_KEYTAB
=
"authentication.keytab"
;
@Override
public
void
contextDestroyed
(
ServletContextEvent
servletContextEvent
)
{
}
/**
* Perform a SIMPLE login based on established OS identity or a kerberos based login using the configured
* principal and keytab (via application.properties).
* @param servletContextEvent
*/
@Override
public
void
contextInitialized
(
ServletContextEvent
servletContextEvent
)
{
// first, let's see if we're running in a hadoop cluster and have the env configured
boolean
isHadoopCluster
=
isHadoopCluster
();
Configuration
hadoopConfig
=
isHadoopCluster
?
getHadoopConfiguration
()
:
new
Configuration
(
false
);
PropertiesConfiguration
configuration
=
null
;
try
{
configuration
=
getPropertiesConfiguration
();
}
catch
(
ConfigurationException
e
)
{
LOG
.
warn
(
"Error reading application configuration"
,
e
);
}
if
(!
isHadoopCluster
)
{
// need to read the configured authentication choice and create the UGI configuration
String
authMethod
;
authMethod
=
configuration
!=
null
?
configuration
.
getString
(
AUTHENTICATION_METHOD
)
:
null
;
// getString may return null, and would like to log the nature of the default setting
if
(
authMethod
==
null
)
{
LOG
.
info
(
"No authentication method configured. Defaulting to simple authentication"
);
authMethod
=
"simple"
;
}
SecurityUtil
.
setAuthenticationMethod
(
UserGroupInformation
.
AuthenticationMethod
.
valueOf
(
authMethod
.
toUpperCase
()),
hadoopConfig
);
}
UserGroupInformation
.
setConfiguration
(
hadoopConfig
);
UserGroupInformation
ugi
=
null
;
UserGroupInformation
.
AuthenticationMethod
authenticationMethod
=
SecurityUtil
.
getAuthenticationMethod
(
hadoopConfig
);
try
{
if
(
authenticationMethod
==
UserGroupInformation
.
AuthenticationMethod
.
SIMPLE
)
{
UserGroupInformation
.
loginUserFromSubject
(
null
);
}
else
if
(
authenticationMethod
==
UserGroupInformation
.
AuthenticationMethod
.
KERBEROS
)
{
UserGroupInformation
.
loginUserFromKeytab
(
getServerPrincipal
(
configuration
.
getString
(
AUTHENTICATION_PRINCIPAL
)),
configuration
.
getString
(
AUTHENTICATION_KEYTAB
));
}
LOG
.
info
(
"Logged in user {}"
,
UserGroupInformation
.
getLoginUser
());
}
catch
(
IOException
e
)
{
throw
new
IllegalStateException
(
String
.
format
(
"Unable to perform %s login."
,
authenticationMethod
),
e
);
}
}
/**
* Return a server (service) principal. The token "_HOST" in the principal will be replaced with the local host
* name (e.g. dgi/_HOST will be changed to dgi/localHostName)
* @param principal the input principal containing an option "_HOST" token
* @return the service principal.
* @throws IOException
*/
private
String
getServerPrincipal
(
String
principal
)
throws
IOException
{
return
SecurityUtil
.
getServerPrincipal
(
principal
,
InetAddress
.
getLocalHost
().
getHostName
());
}
/**
* Returns a Hadoop configuration instance.
* @return the configuration.
*/
protected
Configuration
getHadoopConfiguration
()
{
return
new
Configuration
();
}
/**
* Returns the metadata application configuration.
* @return the metadata configuration.
* @throws ConfigurationException
*/
protected
PropertiesConfiguration
getPropertiesConfiguration
()
throws
ConfigurationException
{
return
new
PropertiesConfiguration
(
"application.properties"
);
}
/**
* Uses a hadoop shell to discern whether a hadoop cluster is available/configured.
* @return true if a hadoop cluster is detected.
*/
protected
boolean
isHadoopCluster
()
{
boolean
isHadoopCluster
=
false
;
try
{
isHadoopCluster
=
Shell
.
getHadoopHome
()
!=
null
;
}
catch
(
IOException
e
)
{
// ignore - false is default setting
}
return
isHadoopCluster
;
}
}
webapp/src/main/webapp/WEB-INF/web.xml
View file @
403c04b3
...
@@ -48,6 +48,9 @@
...
@@ -48,6 +48,9 @@
</filter-mapping>
</filter-mapping>
<listener>
<listener>
<listener-class>
org.apache.hadoop.metadata.web.listeners.LoginListener
</listener-class>
</listener>
<listener>
<listener-class>
org.apache.hadoop.metadata.web.listeners.GuiceServletConfig
</listener-class>
<listener-class>
org.apache.hadoop.metadata.web.listeners.GuiceServletConfig
</listener-class>
</listener>
</listener>
</web-app>
</web-app>
webapp/src/test/java/org/apache/hadoop/metadata/web/listeners/LoginListenerIT.java
0 → 100644
View file @
403c04b3
/*
* 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.
*/
package
org
.
apache
.
hadoop
.
metadata
.
web
.
listeners
;
import
org.apache.commons.configuration.ConfigurationException
;
import
org.apache.commons.configuration.PropertiesConfiguration
;
import
org.apache.commons.io.FileUtils
;
import
org.apache.hadoop.conf.Configuration
;
import
org.apache.hadoop.fs.CommonConfigurationKeysPublic
;
import
org.apache.hadoop.minikdc.MiniKdc
;
import
org.apache.hadoop.security.UserGroupInformation
;
import
org.apache.hadoop.util.Shell
;
import
org.apache.zookeeper.Environment
;
import
org.testng.annotations.Test
;
import
java.io.File
;
import
java.nio.file.Files
;
import
java.util.Locale
;
import
java.util.Properties
;
/**
*
*/
public
class
LoginListenerIT
{
private
static
final
String
JAAS_ENTRY
=
"%s { \n"
+
" %s required\n"
// kerberos module
+
" keyTab=\"%s\"\n"
+
" debug=true\n"
+
" principal=\"%s\"\n"
+
" useKeyTab=true\n"
+
" useTicketCache=false\n"
+
" doNotPrompt=true\n"
+
" storeKey=true;\n"
+
"}; \n"
;
protected
static
final
String
kerberosRule
=
"RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//\nDEFAULT"
;
private
MiniKdc
kdc
;
@Test
public
void
testDefaultSimpleLogin
()
throws
Exception
{
LoginListener
listener
=
new
LoginListener
()
{
@Override
protected
PropertiesConfiguration
getPropertiesConfiguration
()
throws
ConfigurationException
{
return
new
PropertiesConfiguration
();
}
};
listener
.
contextInitialized
(
null
);
assert
UserGroupInformation
.
getCurrentUser
()
!=
null
;
assert
!
UserGroupInformation
.
isLoginKeytabBased
();
assert
!
UserGroupInformation
.
isSecurityEnabled
();
}
@Test
public
void
testKerberosLogin
()
throws
Exception
{
final
File
keytab
=
setupKDCAndPrincipals
();
LoginListener
listener
=
new
LoginListener
()
{
@Override
protected
PropertiesConfiguration
getPropertiesConfiguration
()
throws
ConfigurationException
{
PropertiesConfiguration
config
=
new
PropertiesConfiguration
();
config
.
setProperty
(
"authentication.method"
,
"kerberos"
);
config
.
setProperty
(
"authentication.principal"
,
"dgi@EXAMPLE.COM"
);
config
.
setProperty
(
"authentication.keytab"
,
keytab
.
getAbsolutePath
());
return
config
;
}
@Override
protected
Configuration
getHadoopConfiguration
()
{
Configuration
config
=
new
Configuration
(
false
);
config
.
set
(
CommonConfigurationKeysPublic
.
HADOOP_SECURITY_AUTHENTICATION
,
"kerberos"
);
config
.
setBoolean
(
CommonConfigurationKeysPublic
.
HADOOP_SECURITY_AUTHORIZATION
,
true
);
config
.
set
(
CommonConfigurationKeysPublic
.
HADOOP_SECURITY_AUTH_TO_LOCAL
,
kerberosRule
);
return
config
;
}
@Override
protected
boolean
isHadoopCluster
()
{
return
true
;
}
};
listener
.
contextInitialized
(
null
);
assert
UserGroupInformation
.
getLoginUser
().
getShortUserName
().
endsWith
(
"dgi"
);
assert
UserGroupInformation
.
getCurrentUser
()
!=
null
;
assert
UserGroupInformation
.
isLoginKeytabBased
();
assert
UserGroupInformation
.
isSecurityEnabled
();
kdc
.
stop
();
}
private
File
setupKDCAndPrincipals
()
throws
Exception
{
// set up the KDC
File
target
=
Files
.
createTempDirectory
(
"sectest"
).
toFile
();
File
kdcWorkDir
=
new
File
(
target
,
"kdc"
);
Properties
kdcConf
=
MiniKdc
.
createConf
();
kdcConf
.
setProperty
(
MiniKdc
.
DEBUG
,
"true"
);
kdc
=
new
MiniKdc
(
kdcConf
,
kdcWorkDir
);
kdc
.
start
();
assert
kdc
.
getRealm
()
!=
null
;
File
keytabFile
=
createKeytab
(
kdc
,
kdcWorkDir
,
"dgi"
,
"dgi.keytab"
);
String
dgiServerPrincipal
=
Shell
.
WINDOWS
?
"dgi/127.0.0.1"
:
"dgi/localhost"
;
StringBuilder
jaas
=
new
StringBuilder
(
1024
);
jaas
.
append
(
createJAASEntry
(
"Client"
,
"dgi"
,
keytabFile
));
jaas
.
append
(
createJAASEntry
(
"Server"
,
dgiServerPrincipal
,
keytabFile
));
File
jaasFile
=
new
File
(
kdcWorkDir
,
"jaas.txt"
);
FileUtils
.
write
(
jaasFile
,
jaas
.
toString
());
bindJVMtoJAASFile
(
jaasFile
);
return
keytabFile
;
}
private
File
createKeytab
(
MiniKdc
kdc
,
File
kdcWorkDir
,
String
principal
,
String
filename
)
throws
Exception
{
File
keytab
=
new
File
(
kdcWorkDir
,
filename
);
kdc
.
createPrincipal
(
keytab
,
principal
,
principal
+
"/localhost"
,
principal
+
"/127.0.0.1"
);
return
keytab
;
}
public
String
createJAASEntry
(
String
context
,
String
principal
,
File
keytab
)
{
String
keytabpath
=
keytab
.
getAbsolutePath
();
// fix up for windows; no-op on unix
keytabpath
=
keytabpath
.
replace
(
'\\'
,
'/'
);
return
String
.
format
(
Locale
.
ENGLISH
,
JAAS_ENTRY
,
context
,
getKerberosAuthModuleForJVM
(),
keytabpath
,
principal
);
}
private
String
getKerberosAuthModuleForJVM
()
{
if
(
System
.
getProperty
(
"java.vendor"
).
contains
(
"IBM"
))
{
return
"com.ibm.security.auth.module.Krb5LoginModule"
;
}
else
{
return
"com.sun.security.auth.module.Krb5LoginModule"
;
}
}
private
void
bindJVMtoJAASFile
(
File
jaasFile
)
{
String
path
=
jaasFile
.
getAbsolutePath
();
System
.
setProperty
(
Environment
.
JAAS_CONF_KEY
,
path
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment