Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
jenkins
提交
f09d00dd
J
jenkins
项目概览
xxadev
/
jenkins
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jenkins
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f09d00dd
编写于
9月 24, 2017
作者:
O
Oliver Gondža
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of github.com:jenkinsci/jenkins
上级
5ec4515e
49de269d
变更
21
隐藏空白更改
内联
并排
Showing
21 changed file
with
543 addition
and
245 deletion
+543
-245
cli/src/main/java/hudson/cli/CLI.java
cli/src/main/java/hudson/cli/CLI.java
+17
-1
cli/src/main/java/hudson/cli/FullDuplexHttpStream.java
cli/src/main/java/hudson/cli/FullDuplexHttpStream.java
+15
-69
cli/src/main/java/hudson/cli/PlainCLIProtocol.java
cli/src/main/java/hudson/cli/PlainCLIProtocol.java
+0
-8
core/src/main/java/hudson/Util.java
core/src/main/java/hudson/Util.java
+19
-0
core/src/main/java/hudson/WebAppMain.java
core/src/main/java/hudson/WebAppMain.java
+0
-2
core/src/main/java/hudson/model/Api.java
core/src/main/java/hudson/model/Api.java
+4
-1
core/src/main/java/hudson/model/Job.java
core/src/main/java/hudson/model/Job.java
+36
-0
core/src/main/java/hudson/model/ListView.java
core/src/main/java/hudson/model/ListView.java
+5
-1
core/src/main/java/hudson/security/csrf/CrumbIssuer.java
core/src/main/java/hudson/security/csrf/CrumbIssuer.java
+1
-0
core/src/main/java/jenkins/model/Jenkins.java
core/src/main/java/jenkins/model/Jenkins.java
+21
-5
core/src/main/java/jenkins/util/FullDuplexHttpService.java
core/src/main/java/jenkins/util/FullDuplexHttpService.java
+4
-0
core/src/test/java/hudson/UtilTest.java
core/src/test/java/hudson/UtilTest.java
+38
-0
test/pom.xml
test/pom.xml
+8
-0
test/src/test/java/hudson/cli/CLIActionTest.java
test/src/test/java/hudson/cli/CLIActionTest.java
+0
-17
test/src/test/java/hudson/model/JobTest.java
test/src/test/java/hudson/model/JobTest.java
+111
-1
test/src/test/java/hudson/model/ListViewTest.java
test/src/test/java/hudson/model/ListViewTest.java
+26
-0
test/src/test/java/hudson/security/HudsonPrivateSecurityRealm2Test.java
...java/hudson/security/HudsonPrivateSecurityRealm2Test.java
+0
-118
test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java
.../java/hudson/security/HudsonPrivateSecurityRealmTest.java
+105
-17
test/src/test/java/jenkins/install/InstallUtilTest.java
test/src/test/java/jenkins/install/InstallUtilTest.java
+5
-5
test/src/test/java/jenkins/model/JenkinsTest.java
test/src/test/java/jenkins/model/JenkinsTest.java
+16
-0
test/src/test/java/jenkins/util/FullDuplexHttpServiceTest.java
...src/test/java/jenkins/util/FullDuplexHttpServiceTest.java
+112
-0
未找到文件。
cli/src/main/java/hudson/cli/CLI.java
浏览文件 @
f09d00dd
...
...
@@ -549,7 +549,7 @@ public class CLI implements AutoCloseable {
for
(
Handler
h
:
Logger
.
getLogger
(
""
).
getHandlers
())
{
h
.
setLevel
(
level
);
}
for
(
Logger
logger
:
new
Logger
[]
{
LOGGER
,
PlainCLIProtocol
.
LOGGER
,
Logger
.
getLogger
(
"org.apache.sshd"
)})
{
// perhaps also Channel
for
(
Logger
logger
:
new
Logger
[]
{
LOGGER
,
FullDuplexHttpStream
.
LOGGER
,
PlainCLIProtocol
.
LOGGER
,
Logger
.
getLogger
(
"org.apache.sshd"
)})
{
// perhaps also Channel
logger
.
setLevel
(
level
);
}
args
=
args
.
subList
(
2
,
args
.
size
());
...
...
@@ -704,6 +704,22 @@ public class CLI implements AutoCloseable {
}
}
}.
start
();
new
Thread
(
"ping"
)
{
// JENKINS-46659
@Override
public
void
run
()
{
try
{
Thread
.
sleep
(
10_000
);
while
(!
connection
.
complete
)
{
LOGGER
.
fine
(
"sending ping"
);
connection
.
sendEncoding
(
Charset
.
defaultCharset
().
name
());
// no-op at this point
Thread
.
sleep
(
10_000
);
}
}
catch
(
IOException
|
InterruptedException
x
)
{
LOGGER
.
log
(
Level
.
WARNING
,
null
,
x
);
}
}
}.
start
();
synchronized
(
connection
)
{
while
(!
connection
.
complete
)
{
connection
.
wait
();
...
...
cli/src/main/java/hudson/cli/FullDuplexHttpStream.java
浏览文件 @
f09d00dd
package
hudson.cli
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.io.OutputStream
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
...
...
@@ -16,7 +14,7 @@ import org.apache.commons.codec.binary.Base64;
/**
* Creates a capacity-unlimited bi-directional {@link InputStream}/{@link OutputStream} pair over
* HTTP, which is a request/response protocol.
*
*
{@code FullDuplexHttpService} is the counterpart on the server side.
* @author Kohsuke Kawaguchi
*/
public
class
FullDuplexHttpStream
{
...
...
@@ -29,10 +27,18 @@ public class FullDuplexHttpStream {
private
final
OutputStream
output
;
private
final
InputStream
input
;
/**
* A way to get data from the server.
* There will be an initial zero byte used as a handshake which you should expect and ignore.
*/
public
InputStream
getInputStream
()
{
return
input
;
}
/**
* A way to upload data to the server.
* You will need to write to this and {@link OutputStream#flush} it to finish establishing a connection.
*/
public
OutputStream
getOutputStream
()
{
return
output
;
}
...
...
@@ -79,11 +85,10 @@ public class FullDuplexHttpStream {
URL
target
=
new
URL
(
this
.
base
,
relativeTarget
);
CrumbData
crumbData
=
new
CrumbData
();
UUID
uuid
=
UUID
.
randomUUID
();
// so that the server can correlate those two connections
// server->client
LOGGER
.
fine
(
"establishing download side"
);
HttpURLConnection
con
=
(
HttpURLConnection
)
target
.
openConnection
();
con
.
setDoOutput
(
true
);
// request POST to avoid caching
con
.
setRequestMethod
(
"POST"
);
...
...
@@ -92,17 +97,16 @@ public class FullDuplexHttpStream {
if
(
authorization
!=
null
)
{
con
.
addRequestProperty
(
"Authorization"
,
authorization
);
}
if
(
crumbData
.
isValid
)
{
con
.
addRequestProperty
(
crumbData
.
crumbName
,
crumbData
.
crumb
);
}
con
.
getOutputStream
().
close
();
input
=
con
.
getInputStream
();
// make sure we hit the right URL
// make sure we hit the right URL
; no need for CLI.verifyJenkinsConnection here
if
(
con
.
getHeaderField
(
"Hudson-Duplex"
)
==
null
)
{
throw
new
CLI
.
NotTalkingToJenkinsException
(
"There's no Jenkins running at "
+
target
+
", or is not serving the HTTP Duplex transport"
);
}
LOGGER
.
fine
(
"established download side"
);
// calling getResponseCode or getHeaderFields breaks everything
// client->server uses chunked encoded POST for unlimited capacity.
// client->server uses chunked encoded POST for unlimited capacity.
LOGGER
.
fine
(
"establishing upload side"
);
con
=
(
HttpURLConnection
)
target
.
openConnection
();
con
.
setDoOutput
(
true
);
// request POST
con
.
setRequestMethod
(
"POST"
);
...
...
@@ -113,11 +117,8 @@ public class FullDuplexHttpStream {
if
(
authorization
!=
null
)
{
con
.
addRequestProperty
(
"Authorization"
,
authorization
);
}
if
(
crumbData
.
isValid
)
{
con
.
addRequestProperty
(
crumbData
.
crumbName
,
crumbData
.
crumb
);
}
output
=
con
.
getOutputStream
();
LOGGER
.
fine
(
"established upload side"
);
}
// As this transport mode is using POST, it is necessary to resolve possible redirections using GET first.
...
...
@@ -141,59 +142,4 @@ public class FullDuplexHttpStream {
static
final
int
BLOCK_SIZE
=
1024
;
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
FullDuplexHttpStream
.
class
.
getName
());
private
final
class
CrumbData
{
String
crumbName
;
String
crumb
;
boolean
isValid
;
private
CrumbData
()
{
this
.
crumbName
=
""
;
this
.
crumb
=
""
;
this
.
isValid
=
false
;
getData
();
}
private
void
getData
()
{
try
{
String
base
=
createCrumbUrlBase
();
String
[]
pair
=
readData
(
base
+
"?xpath=concat(//crumbRequestField,\":\",//crumb)"
).
split
(
":"
,
2
);
crumbName
=
pair
[
0
];
crumb
=
pair
[
1
];
isValid
=
true
;
LOGGER
.
fine
(
"Crumb data: "
+
crumbName
+
"="
+
crumb
);
}
catch
(
IOException
e
)
{
// presumably this Hudson doesn't use crumb
LOGGER
.
log
(
Level
.
FINE
,
"Failed to get crumb data"
,
e
);
}
}
private
String
createCrumbUrlBase
()
{
return
base
+
"crumbIssuer/api/xml/"
;
}
private
String
readData
(
String
dest
)
throws
IOException
{
HttpURLConnection
con
=
(
HttpURLConnection
)
new
URL
(
dest
).
openConnection
();
if
(
authorization
!=
null
)
{
con
.
addRequestProperty
(
"Authorization"
,
authorization
);
}
CLI
.
verifyJenkinsConnection
(
con
);
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
con
.
getInputStream
())))
{
String
line
=
reader
.
readLine
();
String
nextLine
=
reader
.
readLine
();
if
(
nextLine
!=
null
)
{
System
.
err
.
println
(
"Warning: received junk from "
+
dest
);
System
.
err
.
println
(
line
);
System
.
err
.
println
(
nextLine
);
while
((
nextLine
=
reader
.
readLine
())
!=
null
)
{
System
.
err
.
println
(
nextLine
);
}
}
return
line
;
}
finally
{
con
.
disconnect
();
}
}
}
}
cli/src/main/java/hudson/cli/PlainCLIProtocol.java
浏览文件 @
f09d00dd
...
...
@@ -34,7 +34,6 @@ import java.io.InputStream;
import
java.io.OutputStream
;
import
java.nio.channels.ClosedChannelException
;
import
java.nio.channels.ReadPendingException
;
import
java.util.concurrent.TimeoutException
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.apache.commons.io.IOUtils
;
...
...
@@ -112,13 +111,6 @@ class PlainCLIProtocol {
}
catch
(
EOFException
x
)
{
handleClose
();
break
;
// TODO verify that we hit EOF immediately, not partway into framelen
}
catch
(
IOException
x
)
{
if
(
x
.
getCause
()
instanceof
TimeoutException
)
{
// TODO on Tomcat this seems to be SocketTimeoutException
LOGGER
.
log
(
Level
.
FINE
,
"ignoring idle timeout, perhaps from Jetty"
,
x
);
continue
;
}
else
{
throw
x
;
}
}
if
(
framelen
<
0
)
{
throw
new
IOException
(
"corrupt stream: negative frame length"
);
...
...
core/src/main/java/hudson/Util.java
浏览文件 @
f09d00dd
...
...
@@ -567,6 +567,25 @@ public class Util {
return
true
;
}
/**
* A check if a file path is a descendant of a parent path
* @param forParent the parent the child should be a descendant of
* @param potentialChild the path to check
* @return true if so
* @throws IOException for invalid paths
* @since FIXME
* @see InvalidPathException
*/
public
static
boolean
isDescendant
(
File
forParent
,
File
potentialChild
)
throws
IOException
{
try
{
Path
child
=
potentialChild
.
getAbsoluteFile
().
toPath
().
normalize
();
Path
parent
=
forParent
.
getAbsoluteFile
().
toPath
().
normalize
();
return
child
.
startsWith
(
parent
);
}
catch
(
InvalidPathException
e
)
{
throw
new
IOException
(
e
);
}
}
/**
* Creates a new temporary directory.
*/
...
...
core/src/main/java/hudson/WebAppMain.java
浏览文件 @
f09d00dd
...
...
@@ -31,7 +31,6 @@ import java.nio.file.StandardOpenOption;
import
jenkins.util.SystemProperties
;
import
com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider
;
import
com.thoughtworks.xstream.core.JVM
;
import
com.trilead.ssh2.util.IOUtils
;
import
hudson.model.Hudson
;
import
hudson.security.ACL
;
import
hudson.util.BootFailure
;
...
...
@@ -62,7 +61,6 @@ import javax.servlet.ServletResponse;
import
javax.xml.transform.TransformerFactory
;
import
javax.xml.transform.TransformerFactoryConfigurationError
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.net.URL
;
import
java.net.URLClassLoader
;
...
...
core/src/main/java/hudson/model/Api.java
浏览文件 @
f09d00dd
...
...
@@ -53,6 +53,8 @@ import java.net.HttpURLConnection;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.kohsuke.accmod.Restricted
;
import
org.kohsuke.accmod.restrictions.NoExternalUse
;
/**
* Used to expose remote access API for ".../api/"
...
...
@@ -228,7 +230,8 @@ public class Api extends AbstractModelObject {
return
false
;
}
private
void
setHeaders
(
StaplerResponse
rsp
)
{
@Restricted
(
NoExternalUse
.
class
)
protected
void
setHeaders
(
StaplerResponse
rsp
)
{
rsp
.
setHeader
(
"X-Jenkins"
,
Jenkins
.
VERSION
);
rsp
.
setHeader
(
"X-Jenkins-Session"
,
Jenkins
.
SESSION_HASH
);
}
...
...
core/src/main/java/hudson/model/Job.java
浏览文件 @
f09d00dd
...
...
@@ -29,6 +29,7 @@ import hudson.EnvVars;
import
hudson.Extension
;
import
hudson.ExtensionPoint
;
import
hudson.FeedAdapter
;
import
hudson.FilePath
;
import
hudson.PermalinkList
;
import
hudson.Util
;
import
hudson.cli.declarative.CLIResolver
;
...
...
@@ -68,6 +69,7 @@ import java.awt.Paint;
import
java.io.File
;
import
java.io.IOException
;
import
java.net.URLEncoder
;
import
java.nio.file.Files
;
import
java.util.ArrayList
;
import
java.util.Calendar
;
import
java.util.Collection
;
...
...
@@ -680,6 +682,40 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
Util
.
deleteRecursive
(
getBuildDir
());
}
@Restricted
(
NoExternalUse
.
class
)
@Extension
public
static
class
SubItemBuildsLocationImpl
extends
ItemListener
{
@Override
public
void
onLocationChanged
(
Item
item
,
String
oldFullName
,
String
newFullName
)
{
final
Jenkins
jenkins
=
Jenkins
.
getInstance
();
if
(!
jenkins
.
isDefaultBuildDir
()
&&
item
instanceof
Job
)
{
File
newBuildDir
=
((
Job
)
item
).
getBuildDir
();
try
{
if
(!
Util
.
isDescendant
(
item
.
getRootDir
(),
newBuildDir
))
{
//OK builds are stored somewhere outside of the item's root, so none of the other move operations has probably moved it.
//So let's try even though we lack some information
String
oldBuildsDir
=
Jenkins
.
expandVariablesForDirectory
(
jenkins
.
getRawBuildsDir
(),
oldFullName
,
"<NOPE>"
);
if
(
oldBuildsDir
.
contains
(
"<NOPE>"
))
{
LOGGER
.
severe
(
String
.
format
(
"Builds directory for job %1$s appears to be outside of item root,"
+
" but somehow still containing the item root path, which is unknown. Cannot move builds from %2$s to %1$s."
,
newFullName
,
oldFullName
));
}
else
{
File
oldDir
=
new
File
(
oldBuildsDir
);
if
(
oldDir
.
isDirectory
())
{
try
{
FileUtils
.
moveDirectory
(
oldDir
,
newBuildDir
);
}
catch
(
IOException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
String
.
format
(
"Failed to move %s to %s"
,
oldBuildsDir
,
newBuildDir
.
getAbsolutePath
()),
e
);
}
}
}
}
}
catch
(
IOException
e
)
{
LOGGER
.
log
(
Level
.
WARNING
,
"Failed to inspect "
+
item
.
getRootDir
()
+
". Builds might not be moved."
,
e
);
}
}
}
}
/**
* Returns true if we should display "build now" icon
*/
...
...
core/src/main/java/hudson/model/ListView.java
浏览文件 @
f09d00dd
...
...
@@ -45,6 +45,7 @@ import java.util.logging.Logger;
import
java.util.regex.Pattern
;
import
java.util.regex.PatternSyntaxException
;
import
javax.annotation.CheckForNull
;
import
javax.annotation.concurrent.GuardedBy
;
import
javax.servlet.ServletException
;
import
jenkins.model.Jenkins
;
...
...
@@ -378,13 +379,16 @@ public class ListView extends View implements DirectlyModifiableView {
throw
new
Failure
(
"Query parameter 'name' is required"
);
TopLevelItem
item
=
resolveName
(
name
);
if
(
item
==
null
)
throw
new
Failure
(
"Query parameter 'name' does not correspond to a known and readable item"
);
if
(
remove
(
item
))
owner
.
save
();
return
HttpResponses
.
ok
();
}
private
TopLevelItem
resolveName
(
String
name
)
{
private
@CheckForNull
TopLevelItem
resolveName
(
String
name
)
{
TopLevelItem
item
=
getOwner
().
getItemGroup
().
getItem
(
name
);
if
(
item
==
null
)
{
name
=
Items
.
getCanonicalName
(
getOwner
().
getItemGroup
(),
name
);
...
...
core/src/main/java/hudson/security/csrf/CrumbIssuer.java
浏览文件 @
f09d00dd
...
...
@@ -193,6 +193,7 @@ public abstract class CrumbIssuer implements Describable<CrumbIssuer>, Extension
}
@Override
public
void
doXml
(
StaplerRequest
req
,
StaplerResponse
rsp
,
@QueryParameter
String
xpath
,
@QueryParameter
String
wrapper
,
@QueryParameter
String
tree
,
@QueryParameter
int
depth
)
throws
IOException
,
ServletException
{
setHeaders
(
rsp
);
String
text
;
CrumbIssuer
ci
=
(
CrumbIssuer
)
bean
;
if
(
"/*/crumbRequestField/text()"
.
equals
(
xpath
))
{
// old FullDuplexHttpStream
...
...
core/src/main/java/jenkins/model/Jenkins.java
浏览文件 @
f09d00dd
...
...
@@ -409,7 +409,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
* This value will be variable-expanded as per {@link #expandVariablesForDirectory}.
* @see #getBuildDirFor(Job)
*/
private
String
buildsDir
=
"${ITEM_ROOTDIR}/builds"
;
private
String
buildsDir
=
DEFAULT_BUILDS_DIR
;
/**
* Message displayed in the top page.
...
...
@@ -2439,12 +2439,22 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
return
expandVariablesForDirectory
(
buildsDir
,
job
);
}
/**
* If the configured buildsDir has it's default value or has been changed.
*
* @return true if default value.
*/
@Restricted
(
NoExternalUse
.
class
)
public
boolean
isDefaultBuildDir
()
{
return
DEFAULT_BUILDS_DIR
.
equals
(
buildsDir
);
}
private
File
expandVariablesForDirectory
(
String
base
,
Item
item
)
{
return
new
File
(
expandVariablesForDirectory
(
base
,
item
.
getFullName
(),
item
.
getRootDir
().
getPath
()));
}
@Restricted
(
NoExternalUse
.
class
)
static
String
expandVariablesForDirectory
(
String
base
,
String
itemFullName
,
String
itemRootDir
)
{
public
static
String
expandVariablesForDirectory
(
String
base
,
String
itemFullName
,
String
itemRootDir
)
{
return
Util
.
replaceMacro
(
base
,
ImmutableMap
.
of
(
"JENKINS_HOME"
,
Jenkins
.
getInstance
().
getRootDir
().
getPath
(),
"ITEM_ROOTDIR"
,
itemRootDir
,
...
...
@@ -3181,6 +3191,8 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
*/
public
synchronized
void
save
()
throws
IOException
{
if
(
BulkChange
.
contains
(
this
))
return
;
version
=
VERSION
;
getConfigFile
().
write
(
this
);
SaveableListener
.
fireOnChange
(
this
,
getConfigFile
());
}
...
...
@@ -3658,9 +3670,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
boolean
result
=
true
;
for
(
Descriptor
<?>
d
:
Functions
.
getSortedDescriptorsForGlobalConfigUnclassified
())
result
&=
configureDescriptor
(
req
,
json
,
d
);
version
=
VERSION
;
save
();
updateComputerList
();
if
(
result
)
...
...
@@ -5068,6 +5078,12 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
*/
private
static
final
String
WORKSPACE_DIRNAME
=
Configuration
.
getStringConfigParameter
(
"workspaceDirName"
,
"workspace"
);
/**
* Default value of job's builds dir.
* @see #getRawBuildsDir()
*/
private
static
final
String
DEFAULT_BUILDS_DIR
=
"${ITEM_ROOTDIR}/builds"
;
/**
* Automatically try to launch an agent when Jenkins is initialized or a new agent computer is created.
*/
...
...
core/src/main/java/jenkins/util/FullDuplexHttpService.java
浏览文件 @
f09d00dd
...
...
@@ -24,6 +24,8 @@
package
jenkins.util
;
import
hudson.cli.FullDuplexHttpStream
;
import
hudson.model.RootAction
;
import
hudson.security.csrf.CrumbExclusion
;
import
hudson.util.ChunkedInputStream
;
import
hudson.util.ChunkedOutputStream
;
import
java.io.IOException
;
...
...
@@ -44,6 +46,8 @@ import org.kohsuke.stapler.StaplerResponse;
/**
* Server-side counterpart to {@link FullDuplexHttpStream}.
* <p>
* To use, bind this to an endpoint with {@link RootAction} (you will also need a {@link CrumbExclusion}).
* @since 2.54
*/
public
abstract
class
FullDuplexHttpService
{
...
...
core/src/test/java/hudson/UtilTest.java
浏览文件 @
f09d00dd
...
...
@@ -672,4 +672,42 @@ public class UtilTest {
}
}
@Test
public
void
testIsDescendant
()
throws
IOException
{
File
root
;
File
other
;
if
(
Functions
.
isWindows
())
{
root
=
new
File
(
"C:\\Temp"
);
other
=
new
File
(
"C:\\Windows"
);
}
else
{
root
=
new
File
(
"/tmp"
);
other
=
new
File
(
"/usr"
);
}
assertTrue
(
Util
.
isDescendant
(
root
,
new
File
(
root
,
"child"
)));
assertTrue
(
Util
.
isDescendant
(
root
,
new
File
(
new
File
(
root
,
"child"
),
"grandchild"
)));
assertFalse
(
Util
.
isDescendant
(
root
,
other
));
assertFalse
(
Util
.
isDescendant
(
root
,
new
File
(
other
,
"child"
)));
assertFalse
(
Util
.
isDescendant
(
new
File
(
root
,
"child"
),
root
));
assertFalse
(
Util
.
isDescendant
(
new
File
(
new
File
(
root
,
"child"
),
"grandchild"
),
root
));
//.. whithin root
File
convoluted
=
new
File
(
root
,
"child"
);
convoluted
=
new
File
(
convoluted
,
".."
);
convoluted
=
new
File
(
convoluted
,
"child"
);
assertTrue
(
Util
.
isDescendant
(
root
,
convoluted
));
//.. going outside of root
convoluted
=
new
File
(
root
,
".."
);
convoluted
=
new
File
(
convoluted
,
other
.
getName
());
convoluted
=
new
File
(
convoluted
,
"child"
);
assertFalse
(
Util
.
isDescendant
(
root
,
convoluted
));
//. on root
assertTrue
(
Util
.
isDescendant
(
new
File
(
root
,
"."
),
new
File
(
root
,
"child"
)));
//. on both
assertTrue
(
Util
.
isDescendant
(
new
File
(
root
,
"."
),
new
File
(
new
File
(
root
,
"child"
),
"."
)));
}
}
test/pom.xml
浏览文件 @
f09d00dd
...
...
@@ -280,6 +280,14 @@ THE SOFTWARE.
</rules>
</configuration>
</plugin>
<plugin>
<!-- https://stackoverflow.com/a/19503679/12916 ysoserial deliberately uses internal APIs; suppress warnings about them -->
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-compiler-plugin
</artifactId>
<configuration>
<compilerArgument>
-XDignore.symbol.file
</compilerArgument>
<fork>
true
</fork>
</configuration>
</plugin>
</plugins>
</build>
...
...
test/src/test/java/hudson/cli/CLIActionTest.java
浏览文件 @
f09d00dd
package
hudson.cli
;
import
com.gargoylesoftware.htmlunit.HttpMethod
;
import
com.gargoylesoftware.htmlunit.Page
;
import
com.gargoylesoftware.htmlunit.WebRequest
;
import
com.gargoylesoftware.htmlunit.WebResponse
;
import
com.google.common.collect.Lists
;
import
hudson.Functions
;
import
hudson.Launcher
;
...
...
@@ -26,7 +22,6 @@ import java.net.URL;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.UUID
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.TimeUnit
;
...
...
@@ -40,7 +35,6 @@ import org.apache.commons.io.output.TeeOutputStream;
import
org.codehaus.groovy.runtime.Security218
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
junit
.
Assert
.*;
import
org.junit.Ignore
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.rules.TemporaryFolder
;
...
...
@@ -122,16 +116,6 @@ public class CLIActionTest {
JenkinsRule
.
WebClient
wc
=
j
.
createWebClient
();
// The behavior changed due to SECURITY-192. index page is no longer accessible to anonymous
wc
.
assertFails
(
"cli"
,
HttpURLConnection
.
HTTP_FORBIDDEN
);
// so we check the access by emulating the CLI connection post request
WebRequest
settings
=
new
WebRequest
(
new
URL
(
j
.
getURL
(),
"cli"
));
settings
.
setHttpMethod
(
HttpMethod
.
POST
);
settings
.
setAdditionalHeader
(
"Session"
,
UUID
.
randomUUID
().
toString
());
settings
.
setAdditionalHeader
(
"Side"
,
"download"
);
// We try to download something to init the duplex channel
Page
page
=
wc
.
getPage
(
settings
);
WebResponse
webResponse
=
page
.
getWebResponse
();
assertEquals
(
"We expect that the proper POST request from CLI gets processed successfully"
,
200
,
webResponse
.
getStatusCode
());
}
@Test
...
...
@@ -256,7 +240,6 @@ public class CLIActionTest {
// -ssh mode does not pass client locale or encoding
}
@Ignore
(
"TODO JENKINS-46659 seems to be broken"
)
@Issue
(
"JENKINS-41745"
)
@Test
public
void
interleavedStdio
()
throws
Exception
{
...
...
test/src/test/java/hudson/model/JobTest.java
浏览文件 @
f09d00dd
...
...
@@ -31,17 +31,25 @@ import com.gargoylesoftware.htmlunit.html.HtmlFormUtil;
import
com.gargoylesoftware.htmlunit.html.HtmlPage
;
import
com.gargoylesoftware.htmlunit.TextPage
;
import
hudson.FilePath
;
import
hudson.Functions
;
import
hudson.model.queue.QueueTaskFuture
;
import
hudson.tasks.ArtifactArchiver
;
import
hudson.tasks.BatchFile
;
import
hudson.tasks.Shell
;
import
hudson.util.TextFile
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.util.concurrent.TimeUnit
;
import
java.io.IOException
;
import
java.net.HttpURLConnection
;
import
java.text.MessageFormat
;
import
java.util.Arrays
;
import
java.util.Comparator
;
import
java.util.concurrent.Callable
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.TimeUnit
;
import
jenkins.model.ProjectNamingStrategy
;
import
org.hamcrest.Matchers
;
...
...
@@ -51,6 +59,7 @@ import org.jvnet.hudson.test.Issue;
import
org.jvnet.hudson.test.FailureBuilder
;
import
org.jvnet.hudson.test.JenkinsRule
;
import
org.jvnet.hudson.test.JenkinsRule.WebClient
;
import
org.jvnet.hudson.test.MockFolder
;
import
org.jvnet.hudson.test.RunLoadCounter
;
import
org.jvnet.hudson.test.SleepBuilder
;
import
org.jvnet.hudson.test.recipes.LocalData
;
...
...
@@ -299,6 +308,107 @@ public class JobTest {
p
.
renameTo
(
"different-name"
);
}
@Issue
(
"JENKINS-44657"
)
@Test
public
void
testRenameWithCustomBuildsDirWithBuildsIntact
()
throws
Exception
{
j
.
jenkins
.
setRawBuildsDir
(
"${JENKINS_HOME}/builds/${ITEM_FULL_NAME}/builds"
);
final
FreeStyleProject
p
=
j
.
createFreeStyleProject
();
final
File
oldBuildsDir
=
p
.
getBuildDir
();
j
.
buildAndAssertSuccess
(
p
);
String
oldDirContent
=
dirContent
(
oldBuildsDir
);
p
.
renameTo
(
"different-name"
);
final
File
newBuildDir
=
p
.
getBuildDir
();
assertNotNull
(
newBuildDir
);
assertNotEquals
(
oldBuildsDir
.
getAbsolutePath
(),
newBuildDir
.
getAbsolutePath
());
String
newDirContent
=
dirContent
(
newBuildDir
);
assertEquals
(
oldDirContent
,
newDirContent
);
}
@Issue
(
"JENKINS-44657"
)
@Test
public
void
testRenameWithCustomBuildsDirWithBuildsIntactInFolder
()
throws
Exception
{
j
.
jenkins
.
setRawBuildsDir
(
"${JENKINS_HOME}/builds/${ITEM_FULL_NAME}/builds"
);
final
MockFolder
f
=
j
.
createFolder
(
"F"
);
final
FreeStyleProject
p1
=
f
.
createProject
(
FreeStyleProject
.
class
,
"P1"
);
j
.
buildAndAssertSuccess
(
p1
);
File
oldP1BuildsDir
=
p1
.
getBuildDir
();
final
String
oldP1DirContent
=
dirContent
(
oldP1BuildsDir
);
f
.
renameTo
(
"different-name"
);
File
newP1BuildDir
=
p1
.
getBuildDir
();
assertNotNull
(
newP1BuildDir
);
assertNotEquals
(
oldP1BuildsDir
.
getAbsolutePath
(),
newP1BuildDir
.
getAbsolutePath
());
String
newP1DirContent
=
dirContent
(
newP1BuildDir
);
assertEquals
(
oldP1DirContent
,
newP1DirContent
);
final
FreeStyleProject
p2
=
f
.
createProject
(
FreeStyleProject
.
class
,
"P2"
);
if
(
Functions
.
isWindows
())
{
p2
.
getBuildersList
().
add
(
new
BatchFile
(
"echo hello > hello.txt"
));
}
else
{
p2
.
getBuildersList
().
add
(
new
Shell
(
"echo hello > hello.txt"
));
}
p2
.
getPublishersList
().
add
(
new
ArtifactArchiver
(
"*.txt"
));
j
.
buildAndAssertSuccess
(
p2
);
File
oldP2BuildsDir
=
p2
.
getBuildDir
();
final
String
oldP2DirContent
=
dirContent
(
oldP2BuildsDir
);
FreeStyleBuild
b2
=
p2
.
getBuilds
().
getLastBuild
();
ByteArrayOutputStream
out
=
new
ByteArrayOutputStream
();
b2
.
getLogText
().
writeRawLogTo
(
0
,
out
);
final
String
oldB2Log
=
new
String
(
out
.
toByteArray
());
assertTrue
(
b2
.
getArtifactManager
().
root
().
child
(
"hello.txt"
).
exists
());
f
.
renameTo
(
"something-else"
);
//P1 check again
newP1BuildDir
=
p1
.
getBuildDir
();
assertNotNull
(
newP1BuildDir
);
assertNotEquals
(
oldP1BuildsDir
.
getAbsolutePath
(),
newP1BuildDir
.
getAbsolutePath
());
newP1DirContent
=
dirContent
(
newP1BuildDir
);
assertEquals
(
oldP1DirContent
,
newP1DirContent
);
//P2 check
b2
=
p2
.
getBuilds
().
getLastBuild
();
assertNotNull
(
b2
);
out
=
new
ByteArrayOutputStream
();
b2
.
getLogText
().
writeRawLogTo
(
0
,
out
);
final
String
newB2Log
=
new
String
(
out
.
toByteArray
());
assertEquals
(
oldB2Log
,
newB2Log
);
assertTrue
(
b2
.
getArtifactManager
().
root
().
child
(
"hello.txt"
).
exists
());
File
newP2BuildDir
=
p2
.
getBuildDir
();
assertNotNull
(
newP2BuildDir
);
assertNotEquals
(
oldP2BuildsDir
.
getAbsolutePath
(),
newP2BuildDir
.
getAbsolutePath
());
String
newP2DirContent
=
dirContent
(
newP2BuildDir
);
assertEquals
(
oldP2DirContent
,
newP2DirContent
);
}
private
String
dirContent
(
File
dir
)
throws
IOException
,
InterruptedException
{
if
(
dir
==
null
||
!
dir
.
isDirectory
())
{
return
null
;
}
StringBuilder
str
=
new
StringBuilder
(
""
);
final
FilePath
[]
list
=
new
FilePath
(
dir
).
list
(
"**/*"
);
Arrays
.
sort
(
list
,
Comparator
.
comparing
(
FilePath:
:
getRemote
));
for
(
FilePath
path
:
list
)
{
str
.
append
(
relativePath
(
dir
,
path
));
str
.
append
(
' '
).
append
(
path
.
length
()).
append
(
'\n'
);
}
return
str
.
toString
();
}
private
String
relativePath
(
File
base
,
FilePath
path
)
throws
IOException
,
InterruptedException
{
if
(
path
.
absolutize
().
getRemote
().
equals
(
base
.
getAbsolutePath
()))
{
return
""
;
}
else
{
final
String
s
=
relativePath
(
base
,
path
.
getParent
());
if
(
s
.
isEmpty
())
{
return
path
.
getName
();
}
else
{
return
s
+
"/"
+
path
.
getName
();
}
}
}
@Issue
(
"JENKINS-30502"
)
@Test
public
void
testRenameTrimsLeadingSpace
()
throws
Exception
{
...
...
test/src/test/java/hudson/model/ListViewTest.java
浏览文件 @
f09d00dd
...
...
@@ -259,6 +259,32 @@ public class ListViewTest {
assertEquals
(
"job1"
,
items
.
get
(
0
).
getName
());
}
@Issue
(
"JENKINS-23411"
)
@Test
public
void
doRemoveJobFromViewNullItem
()
throws
Exception
{
MockFolder
folder
=
j
.
createFolder
(
"folder"
);
ListView
view
=
new
ListView
(
"view"
,
folder
);
folder
.
addView
(
view
);
FreeStyleProject
job
=
folder
.
createProject
(
FreeStyleProject
.
class
,
"job1"
);
view
.
add
(
job
);
List
<
TopLevelItem
>
items
=
view
.
getItems
();
assertEquals
(
1
,
items
.
size
());
assertEquals
(
"job1"
,
items
.
get
(
0
).
getName
());
// remove a contained job
view
.
doRemoveJobFromView
(
"job1"
);
List
<
TopLevelItem
>
itemsNow
=
view
.
getItems
();
assertEquals
(
0
,
itemsNow
.
size
());
// remove a not contained job
try
{
view
.
doRemoveJobFromView
(
"job2"
);
fail
(
"Remove job2"
);
}
catch
(
Failure
e
)
{
assertEquals
(
e
.
getMessage
(),
"Query parameter 'name' does not correspond to a known and readable item"
);
}
}
private
static
class
AllButViewsAuthorizationStrategy
extends
AuthorizationStrategy
{
@Override
public
ACL
getRootACL
()
{
return
UNSECURED
.
getRootACL
();
...
...
test/src/test/java/hudson/security/HudsonPrivateSecurityRealm2Test.java
已删除
100644 → 0
浏览文件 @
5ec4515e
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package
hudson.security
;
import
com.gargoylesoftware.htmlunit.html.HtmlPage
;
import
hudson.model.User
;
import
hudson.security.pages.SignupPage
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.jvnet.hudson.test.JenkinsRule
;
import
java.util.Collections
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
junit
.
Assert
.*;
import
org.jvnet.hudson.test.Issue
;
/**
* Tests the signup page of {@link hudson.security.HudsonPrivateSecurityRealm}
* TODO: Add to {@link hudson.security.HudsonPrivateSecurityRealmTest} going forward
*/
public
class
HudsonPrivateSecurityRealm2Test
{
@Rule
public
JenkinsRule
rule
=
new
JenkinsRule
();
@Test
public
void
signup
()
throws
Exception
{
HudsonPrivateSecurityRealm
securityRealm
=
new
HudsonPrivateSecurityRealm
(
true
,
false
,
null
);
rule
.
jenkins
.
setSecurityRealm
(
securityRealm
);
JenkinsRule
.
WebClient
wc
=
rule
.
createWebClient
();
SignupPage
signup
=
new
SignupPage
(
wc
.
goTo
(
"signup"
));
signup
.
enterUsername
(
"alice"
);
signup
.
enterPassword
(
"alice"
);
signup
.
enterFullName
(
"Alice User"
);
signup
.
enterEmail
(
"alice@nowhere.com"
);
HtmlPage
success
=
signup
.
submit
(
rule
);
assertThat
(
success
.
getElementById
(
"main-panel"
).
getTextContent
(),
containsString
(
"Success"
));
assertThat
(
success
.
getAnchorByHref
(
"/jenkins/user/alice"
).
getTextContent
(),
containsString
(
"Alice User"
));
assertEquals
(
"Alice User"
,
securityRealm
.
getUser
(
"alice"
).
getDisplayName
());
}
@Issue
(
"SECURITY-166"
)
@Test
public
void
anonymousCantSignup
()
throws
Exception
{
HudsonPrivateSecurityRealm
securityRealm
=
new
HudsonPrivateSecurityRealm
(
true
,
false
,
null
);
rule
.
jenkins
.
setSecurityRealm
(
securityRealm
);
JenkinsRule
.
WebClient
wc
=
rule
.
createWebClient
();
SignupPage
signup
=
new
SignupPage
(
wc
.
goTo
(
"signup"
));
signup
.
enterUsername
(
"anonymous"
);
signup
.
enterFullName
(
"Bob"
);
signup
.
enterPassword
(
"nothing"
);
signup
.
enterEmail
(
"noone@nowhere.com"
);
signup
=
new
SignupPage
(
signup
.
submit
(
rule
));
signup
.
assertErrorContains
(
"prohibited as a username"
);
assertNull
(
User
.
get
(
"anonymous"
,
false
,
Collections
.
emptyMap
()));
}
@Issue
(
"SECURITY-166"
)
@Test
public
void
systemCantSignup
()
throws
Exception
{
HudsonPrivateSecurityRealm
securityRealm
=
new
HudsonPrivateSecurityRealm
(
true
,
false
,
null
);
rule
.
jenkins
.
setSecurityRealm
(
securityRealm
);
JenkinsRule
.
WebClient
wc
=
rule
.
createWebClient
();
SignupPage
signup
=
new
SignupPage
(
wc
.
goTo
(
"signup"
));
signup
.
enterUsername
(
"system"
);
signup
.
enterFullName
(
"Bob"
);
signup
.
enterPassword
(
"nothing"
);
signup
.
enterEmail
(
"noone@nowhere.com"
);
signup
=
new
SignupPage
(
signup
.
submit
(
rule
));
signup
.
assertErrorContains
(
"prohibited as a username"
);
assertNull
(
User
.
get
(
"system"
,
false
,
Collections
.
emptyMap
()));
}
/**
* We don't allow prohibited fullnames since this may encumber auditing.
*/
@Issue
(
"SECURITY-166"
)
@Test
public
void
fullNameOfUnknownCantSignup
()
throws
Exception
{
HudsonPrivateSecurityRealm
securityRealm
=
new
HudsonPrivateSecurityRealm
(
true
,
false
,
null
);
rule
.
jenkins
.
setSecurityRealm
(
securityRealm
);
JenkinsRule
.
WebClient
wc
=
rule
.
createWebClient
();
SignupPage
signup
=
new
SignupPage
(
wc
.
goTo
(
"signup"
));
signup
.
enterUsername
(
"unknown2"
);
signup
.
enterPassword
(
"unknown2"
);
signup
.
enterFullName
(
"unknown"
);
signup
.
enterEmail
(
"noone@nowhere.com"
);
signup
=
new
SignupPage
(
signup
.
submit
(
rule
));
signup
.
assertErrorContains
(
"prohibited as a full name"
);
assertNull
(
User
.
get
(
"unknown2"
,
false
,
Collections
.
emptyMap
()));
}
}
test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java
浏览文件 @
f09d00dd
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc. and others
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package
hudson.security
;
import
com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException
;
import
com.gargoylesoftware.htmlunit.html.HtmlPage
;
import
com.gargoylesoftware.htmlunit.xml.XmlPage
;
import
hudson.model.User
;
import
hudson.remoting.Base64
;
import
static
hudson
.
security
.
HudsonPrivateSecurityRealm
.
CLASSIC
;
import
static
hudson
.
security
.
HudsonPrivateSecurityRealm
.
PASSWORD_ENCODER
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
hudson.security.pages.SignupPage
;
import
java.io.UnsupportedEncodingException
;
import
java.util.Collections
;
import
jenkins.security.ApiTokenProperty
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
is
;
import
static
org
.
hamcrest
.
xml
.
HasXPath
.
hasXPath
;
import
java.io.UnsupportedEncodingException
;
import
static
org
.
junit
.
Assert
.*;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.jvnet.hudson.test.Issue
;
...
...
@@ -18,17 +46,7 @@ import org.jvnet.hudson.test.JenkinsRule;
import
org.jvnet.hudson.test.JenkinsRule.WebClient
;
import
org.jvnet.hudson.test.WithoutJenkins
;
import
org.jvnet.hudson.test.recipes.LocalData
;
import
com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException
;
import
com.gargoylesoftware.htmlunit.html.HtmlPage
;
import
com.gargoylesoftware.htmlunit.xml.XmlPage
;
import
hudson.model.User
;
import
hudson.remoting.Base64
;
import
jenkins.security.ApiTokenProperty
;
/**
* @author Kohsuke Kawaguchi
*/
public
class
HudsonPrivateSecurityRealmTest
{
@Rule
...
...
@@ -171,4 +189,74 @@ public class HudsonPrivateSecurityRealmTest {
return
authHeader
;
}
@Test
public
void
signup
()
throws
Exception
{
HudsonPrivateSecurityRealm
securityRealm
=
new
HudsonPrivateSecurityRealm
(
true
,
false
,
null
);
j
.
jenkins
.
setSecurityRealm
(
securityRealm
);
JenkinsRule
.
WebClient
wc
=
j
.
createWebClient
();
SignupPage
signup
=
new
SignupPage
(
wc
.
goTo
(
"signup"
));
signup
.
enterUsername
(
"alice"
);
signup
.
enterPassword
(
"alice"
);
signup
.
enterFullName
(
"Alice User"
);
signup
.
enterEmail
(
"alice@nowhere.com"
);
HtmlPage
success
=
signup
.
submit
(
j
);
assertThat
(
success
.
getElementById
(
"main-panel"
).
getTextContent
(),
containsString
(
"Success"
));
assertThat
(
success
.
getAnchorByHref
(
"/jenkins/user/alice"
).
getTextContent
(),
containsString
(
"Alice User"
));
assertEquals
(
"Alice User"
,
securityRealm
.
getUser
(
"alice"
).
getDisplayName
());
}
@Issue
(
"SECURITY-166"
)
@Test
public
void
anonymousCantSignup
()
throws
Exception
{
HudsonPrivateSecurityRealm
securityRealm
=
new
HudsonPrivateSecurityRealm
(
true
,
false
,
null
);
j
.
jenkins
.
setSecurityRealm
(
securityRealm
);
JenkinsRule
.
WebClient
wc
=
j
.
createWebClient
();
SignupPage
signup
=
new
SignupPage
(
wc
.
goTo
(
"signup"
));
signup
.
enterUsername
(
"anonymous"
);
signup
.
enterFullName
(
"Bob"
);
signup
.
enterPassword
(
"nothing"
);
signup
.
enterEmail
(
"noone@nowhere.com"
);
signup
=
new
SignupPage
(
signup
.
submit
(
j
));
signup
.
assertErrorContains
(
"prohibited as a username"
);
assertNull
(
User
.
get
(
"anonymous"
,
false
,
Collections
.
emptyMap
()));
}
@Issue
(
"SECURITY-166"
)
@Test
public
void
systemCantSignup
()
throws
Exception
{
HudsonPrivateSecurityRealm
securityRealm
=
new
HudsonPrivateSecurityRealm
(
true
,
false
,
null
);
j
.
jenkins
.
setSecurityRealm
(
securityRealm
);
JenkinsRule
.
WebClient
wc
=
j
.
createWebClient
();
SignupPage
signup
=
new
SignupPage
(
wc
.
goTo
(
"signup"
));
signup
.
enterUsername
(
"system"
);
signup
.
enterFullName
(
"Bob"
);
signup
.
enterPassword
(
"nothing"
);
signup
.
enterEmail
(
"noone@nowhere.com"
);
signup
=
new
SignupPage
(
signup
.
submit
(
j
));
signup
.
assertErrorContains
(
"prohibited as a username"
);
assertNull
(
User
.
get
(
"system"
,
false
,
Collections
.
emptyMap
()));
}
/**
* We don't allow prohibited fullnames since this may encumber auditing.
*/
@Issue
(
"SECURITY-166"
)
@Test
public
void
fullNameOfUnknownCantSignup
()
throws
Exception
{
HudsonPrivateSecurityRealm
securityRealm
=
new
HudsonPrivateSecurityRealm
(
true
,
false
,
null
);
j
.
jenkins
.
setSecurityRealm
(
securityRealm
);
JenkinsRule
.
WebClient
wc
=
j
.
createWebClient
();
SignupPage
signup
=
new
SignupPage
(
wc
.
goTo
(
"signup"
));
signup
.
enterUsername
(
"unknown2"
);
signup
.
enterPassword
(
"unknown2"
);
signup
.
enterFullName
(
"unknown"
);
signup
.
enterEmail
(
"noone@nowhere.com"
);
signup
=
new
SignupPage
(
signup
.
submit
(
j
));
signup
.
assertErrorContains
(
"prohibited as a full name"
);
assertNull
(
User
.
get
(
"unknown2"
,
false
,
Collections
.
emptyMap
()));
}
}
test/src/test/java/jenkins/install/InstallUtilTest.java
浏览文件 @
f09d00dd
...
...
@@ -23,7 +23,6 @@
*/
package
jenkins.install
;
import
java.lang.reflect.Field
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.HashMap
;
...
...
@@ -81,6 +80,9 @@ public class InstallUtilTest {
*/
@Test
public
void
test_typeTransitions
()
{
InstallUtil
.
getLastExecVersionFile
().
delete
();
InstallUtil
.
getConfigFile
().
delete
();
// A new test instance sets up security first
Assert
.
assertEquals
(
InstallState
.
INITIAL_SECURITY_SETUP
,
InstallUtil
.
getNextInstallState
(
InstallState
.
UNKNOWN
));
...
...
@@ -127,12 +129,10 @@ public class InstallUtilTest {
}
private
void
setStoredVersion
(
String
version
)
throws
Exception
{
Field
versionField
=
Jenkins
.
class
.
getDeclaredField
(
"version"
);
versionField
.
setAccessible
(
true
);
versionField
.
set
(
jenkinsRule
.
jenkins
,
version
);
Assert
.
assertEquals
(
version
,
Jenkins
.
getStoredVersion
().
toString
());
Jenkins
.
VERSION
=
version
;
// Force a save of the config.xml
jenkinsRule
.
jenkins
.
save
();
Assert
.
assertEquals
(
version
,
Jenkins
.
getStoredVersion
().
toString
());
}
/**
...
...
test/src/test/java/jenkins/model/JenkinsTest.java
浏览文件 @
f09d00dd
...
...
@@ -62,6 +62,7 @@ import hudson.slaves.ComputerListener;
import
hudson.slaves.DumbSlave
;
import
hudson.slaves.OfflineCause
;
import
hudson.util.FormValidation
;
import
hudson.util.VersionNumber
;
import
org.junit.Rule
;
import
org.junit.Test
;
...
...
@@ -601,4 +602,19 @@ public class JenkinsTest {
assertThat
(
protocolToDisable2
+
" must be disabled after the roundtrip"
,
j
.
jenkins
.
getAgentProtocols
(),
not
(
hasItem
(
protocolToDisable2
)));
}
@Issue
(
"JENKINS-42577"
)
@Test
public
void
versionIsSavedInSave
()
throws
Exception
{
Jenkins
.
VERSION
=
"1.0"
;
j
.
jenkins
.
save
();
VersionNumber
storedVersion
=
Jenkins
.
getStoredVersion
();
assertNotNull
(
storedVersion
);
assertEquals
(
storedVersion
.
toString
(),
"1.0"
);
Jenkins
.
VERSION
=
null
;
j
.
jenkins
.
save
();
VersionNumber
nullVersion
=
Jenkins
.
getStoredVersion
();
assertNull
(
nullVersion
);
}
}
test/src/test/java/jenkins/util/FullDuplexHttpServiceTest.java
0 → 100644
浏览文件 @
f09d00dd
/*
* The MIT License
*
* Copyright 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package
jenkins.util
;
import
hudson.cli.FullDuplexHttpStream
;
import
hudson.model.RootAction
;
import
hudson.security.csrf.CrumbExclusion
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.UUID
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.servlet.FilterChain
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.junit.Test
;
import
static
org
.
junit
.
Assert
.*;
import
org.junit.Rule
;
import
org.jvnet.hudson.test.JenkinsRule
;
import
org.jvnet.hudson.test.LoggerRule
;
import
org.jvnet.hudson.test.TestExtension
;
import
org.kohsuke.stapler.HttpResponse
;
import
org.kohsuke.stapler.StaplerRequest
;
public
class
FullDuplexHttpServiceTest
{
@Rule
public
JenkinsRule
r
=
new
JenkinsRule
();
@Rule
public
LoggerRule
logging
=
new
LoggerRule
().
record
(
FullDuplexHttpService
.
class
,
Level
.
FINE
).
record
(
FullDuplexHttpStream
.
class
,
Level
.
FINE
);
@Test
public
void
smokes
()
throws
Exception
{
logging
.
record
(
"org.eclipse.jetty"
,
Level
.
ALL
);
FullDuplexHttpStream
con
=
new
FullDuplexHttpStream
(
r
.
getURL
(),
"test/"
,
null
);
InputStream
is
=
con
.
getInputStream
();
OutputStream
os
=
con
.
getOutputStream
();
os
.
write
(
33
);
os
.
flush
();
Logger
.
getLogger
(
FullDuplexHttpServiceTest
.
class
.
getName
()).
info
(
"uploaded initial content"
);
assertEquals
(
0
,
is
.
read
());
// see FullDuplexHttpStream.getInputStream
assertEquals
(
66
,
is
.
read
());
}
@TestExtension
(
"smokes"
)
public
static
class
Endpoint
implements
RootAction
{
private
transient
final
Map
<
UUID
,
FullDuplexHttpService
>
duplexServices
=
new
HashMap
<>();
@Override
public
String
getUrlName
()
{
return
"test"
;
}
@Override
public
String
getIconFileName
()
{
return
null
;
}
@Override
public
String
getDisplayName
()
{
return
null
;
}
public
HttpResponse
doIndex
()
{
return
new
FullDuplexHttpService
.
Response
(
duplexServices
)
{
@Override
protected
FullDuplexHttpService
createService
(
StaplerRequest
req
,
UUID
uuid
)
throws
IOException
,
InterruptedException
{
return
new
FullDuplexHttpService
(
uuid
)
{
@Override
protected
void
run
(
InputStream
upload
,
OutputStream
download
)
throws
IOException
,
InterruptedException
{
int
x
=
upload
.
read
();
download
.
write
(
x
*
2
);
}
};
}
};
}
}
@TestExtension
(
"smokes"
)
public
static
class
EndpointCrumbExclusion
extends
CrumbExclusion
{
@Override
public
boolean
process
(
HttpServletRequest
request
,
HttpServletResponse
response
,
FilterChain
chain
)
throws
IOException
,
ServletException
{
if
(
"/test/"
.
equals
(
request
.
getPathInfo
()))
{
chain
.
doFilter
(
request
,
response
);
return
true
;
}
return
false
;
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录