Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
LinuxSuRen
jenkins
提交
0fd8808b
J
jenkins
项目概览
LinuxSuRen
/
jenkins
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
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,发现更多精彩内容 >>
未验证
提交
0fd8808b
编写于
3月 09, 2018
作者:
J
Jesse Glick
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' into access-modifier
上级
f57b841f
c84cbf32
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
391 addition
and
181 deletion
+391
-181
core/src/main/java/hudson/Util.java
core/src/main/java/hudson/Util.java
+40
-26
core/src/main/java/hudson/security/AccountCreationFailedException.java
.../java/hudson/security/AccountCreationFailedException.java
+40
-0
core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
...main/java/hudson/security/HudsonPrivateSecurityRealm.java
+78
-21
core/src/main/java/hudson/util/TextFile.java
core/src/main/java/hudson/util/TextFile.java
+14
-35
core/src/main/java/jenkins/install/SetupWizard.java
core/src/main/java/jenkins/install/SetupWizard.java
+40
-34
core/src/main/java/jenkins/security/s2m/ConfigFile.java
core/src/main/java/jenkins/security/s2m/ConfigFile.java
+37
-8
core/src/main/java/jenkins/util/io/LinesStream.java
core/src/main/java/jenkins/util/io/LinesStream.java
+114
-0
pom.xml
pom.xml
+4
-25
war/src/main/js/pluginSetupWizardGui.js
war/src/main/js/pluginSetupWizardGui.js
+23
-31
war/src/main/js/templates/firstUserPanel.hbs
war/src/main/js/templates/firstUserPanel.hbs
+1
-1
未找到文件。
core/src/main/java/hudson/Util.java
浏览文件 @
0fd8808b
...
...
@@ -89,6 +89,9 @@ import javax.annotation.Nullable;
import
javax.crypto.SecretKey
;
import
javax.crypto.spec.SecretKeySpec
;
import
org.apache.commons.codec.digest.DigestUtils
;
import
org.apache.commons.io.FileUtils
;
/**
* Various utility methods that don't have more proper home.
*
...
...
@@ -181,43 +184,54 @@ public class Util {
}
/**
* Loads the contents of a file into a string.
* Reads the entire contents of the text file at <code>logfile</code> into a
* string using the {@link Charset#defaultCharset() default charset} for
* decoding. If no such file exists, an empty string is returned.
* @param logfile The text file to read in its entirety.
* @return The entire text content of <code>logfile</code>.
* @throws IOException If an error occurs while reading the file.
* @deprecated call {@link #loadFile(java.io.File, java.nio.charset.Charset)}
* instead to specify the charset to use for decoding (preferably
* {@link java.nio.charset.StandardCharsets#UTF_8}).
*/
@Nonnull
@Deprecated
public
static
String
loadFile
(
@Nonnull
File
logfile
)
throws
IOException
{
return
loadFile
(
logfile
,
Charset
.
defaultCharset
());
}
/**
* Reads the entire contents of the text file at <code>logfile</code> into a
* string using <code>charset</code> for decoding. If no such file exists,
* an empty string is returned.
* @param logfile The text file to read in its entirety.
* @param charset The charset to use for decoding the bytes in <code>logfile</code>.
* @return The entire text content of <code>logfile</code>.
* @throws IOException If an error occurs while reading the file.
*/
@Nonnull
public
static
String
loadFile
(
@Nonnull
File
logfile
,
@Nonnull
Charset
charset
)
throws
IOException
{
if
(!
logfile
.
exists
())
return
""
;
StringBuilder
str
=
new
StringBuilder
((
int
)
logfile
.
length
());
// We're not using Files.newBufferedReader() here because there is a
// difference in how an InputStreamReader constructed from a Charset and
// the reader returned by Files.newBufferedReader() handle malformed and
// unmappable byte sequences for the specified encoding; the latter is
// more picky and will throw a CharacterCodingException. See:
// https://issues.jenkins-ci.org/browse/JENKINS-49060?focusedCommentId=325989&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-325989
// Note: Until charset handling is resolved (e.g. by implementing
// https://issues.jenkins-ci.org/browse/JENKINS-48923 ), this method
// must be able to handle character encoding errors. As reported at
// https://issues.jenkins-ci.org/browse/JENKINS-49112 Run.getLog() calls
// loadFile() to fully read the generated log file. This file might
// contain unmappable and/or malformed byte sequences. We need to make
// sure that in such cases, no CharacterCodingException is thrown.
//
// As reported at https://issues.jenkins-ci.org/browse/JENKINS-49112
// Run.getLog() calls loadFile() to fully read the generated log file.
// Until charset handling is resolved (e.g. by implementing
// https://issues.jenkins-ci.org/browse/JENKINS-48923 ), malformed
// bytes will need to be tolerated.
try
(
InputStream
rawIn
=
Files
.
newInputStream
(
fileToPath
(
logfile
));
Reader
r
=
new
BufferedReader
(
new
InputStreamReader
(
rawIn
,
charset
)))
{
char
[]
buf
=
new
char
[
1024
];
int
len
;
while
((
len
=
r
.
read
(
buf
,
0
,
buf
.
length
))
>
0
)
str
.
append
(
buf
,
0
,
len
);
// One approach that cannot be used is to call Files.newBufferedReader()
// because there is a difference in how an InputStreamReader constructed
// from a Charset and the reader returned by Files.newBufferedReader()
// handle malformed and unmappable byte sequences for the specified
// encoding; the latter is more picky and will throw an exception.
// See: https://issues.jenkins-ci.org/browse/JENKINS-49060?focusedCommentId=325989&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-325989
try
{
return
FileUtils
.
readFileToString
(
logfile
,
charset
);
}
catch
(
FileNotFoundException
e
)
{
return
""
;
}
catch
(
Exception
e
)
{
throw
new
IOException
(
"Failed to fully read "
+
logfile
+
" using charset "
+
charset
.
name
()
,
e
);
throw
new
IOException
(
"Failed to fully read "
+
logfile
,
e
);
}
return
str
.
toString
();
}
/**
...
...
core/src/main/java/hudson/security/AccountCreationFailedException.java
0 → 100644
浏览文件 @
0fd8808b
/*
* The MIT License
*
* Copyright (c) 2017 Jenkins contributors
*
* 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
org.kohsuke.accmod.Restricted
;
import
org.kohsuke.accmod.restrictions.NoExternalUse
;
/**
* Thrown if an account creation was attempted but failed due to invalid data being entered into a form.
*
* @author Philipp Nowak
*/
@Restricted
(
NoExternalUse
.
class
)
public
class
AccountCreationFailedException
extends
Exception
{
public
AccountCreationFailedException
(
String
message
)
{
super
(
message
);
}
}
core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
浏览文件 @
0fd8808b
...
...
@@ -289,6 +289,26 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
return
u
;
}
/**
* Creates a user account. Intended to be called from the setup wizard.
* Note that this method does not check whether it is actually called from
* the setup wizard. This requires the {@link Jenkins#ADMINISTER} permission.
*
* @param req the request to retrieve input data from
* @return the created user account, never null
* @throws AccountCreationFailedException if account creation failed due to invalid form input
*/
@Restricted
(
NoExternalUse
.
class
)
public
User
createAccountFromSetupWizard
(
StaplerRequest
req
)
throws
IOException
,
AccountCreationFailedException
{
checkPermission
(
Jenkins
.
ADMINISTER
);
SignupInfo
si
=
validateAccountCreationForm
(
req
,
false
);
if
(
si
.
errorMessage
!=
null
)
{
throw
new
AccountCreationFailedException
(
si
.
errorMessage
);
}
else
{
return
createAccount
(
si
);
}
}
/**
* Creates a first admin user account.
*
...
...
@@ -321,65 +341,102 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
}
/**
* @param req the request to get the form data from (is also used for redirection)
* @param rsp the response to use for forwarding if the creation fails
* @param validateCaptcha whether to attempt to validate a captcha in the request
* @param formView the view to redirect to if creation fails
*
* @return
* null if failed. The browser is already redirected to retry by the time this method returns.
* a valid {@link User} object if the user creation was successful.
*/
private
User
createAccount
(
StaplerRequest
req
,
StaplerResponse
rsp
,
boolean
selfRegistration
,
String
formView
)
throws
ServletException
,
IOException
{
private
User
createAccount
(
StaplerRequest
req
,
StaplerResponse
rsp
,
boolean
validateCaptcha
,
String
formView
)
throws
ServletException
,
IOException
{
SignupInfo
si
=
validateAccountCreationForm
(
req
,
validateCaptcha
);
if
(
si
.
errorMessage
!=
null
)
{
// failed. ask the user to try again.
req
.
getView
(
this
,
formView
).
forward
(
req
,
rsp
);
return
null
;
}
return
createAccount
(
si
);
}
/**
* @param req the request to process
* @param validateCaptcha whether to attempt to validate a captcha in the request
*
* @return a {@link SignupInfo#SignupInfo(StaplerRequest) SignupInfo from given request}, with {@link
* SignupInfo#errorMessage} set to a non-null value if any of the supported fields are invalid
*/
private
SignupInfo
validateAccountCreationForm
(
StaplerRequest
req
,
boolean
validateCaptcha
)
{
// form field validation
// this pattern needs to be generalized and moved to stapler
SignupInfo
si
=
new
SignupInfo
(
req
);
if
(
selfRegistration
&&
!
validateCaptcha
(
si
.
captcha
))
if
(
validateCaptcha
&&
!
validateCaptcha
(
si
.
captcha
))
{
si
.
errorMessage
=
Messages
.
HudsonPrivateSecurityRealm_CreateAccount_TextNotMatchWordInImage
();
}
if
(
si
.
password1
!=
null
&&
!
si
.
password1
.
equals
(
si
.
password2
))
if
(
si
.
password1
!=
null
&&
!
si
.
password1
.
equals
(
si
.
password2
))
{
si
.
errorMessage
=
Messages
.
HudsonPrivateSecurityRealm_CreateAccount_PasswordNotMatch
();
}
if
(!(
si
.
password1
!=
null
&&
si
.
password1
.
length
()
!=
0
))
if
(!(
si
.
password1
!=
null
&&
si
.
password1
.
length
()
!=
0
))
{
si
.
errorMessage
=
Messages
.
HudsonPrivateSecurityRealm_CreateAccount_PasswordRequired
();
}
if
(
si
.
username
==
null
||
si
.
username
.
length
()==
0
)
if
(
si
.
username
==
null
||
si
.
username
.
length
()
==
0
)
{
si
.
errorMessage
=
Messages
.
HudsonPrivateSecurityRealm_CreateAccount_UserNameRequired
();
else
{
}
else
{
// do not create the user - we just want to check if the user already exists but is not a "login" user.
User
user
=
User
.
getById
(
si
.
username
,
false
);
User
user
=
User
.
getById
(
si
.
username
,
false
);
if
(
null
!=
user
)
// Allow sign up. SCM people has no such property.
if
(
user
.
getProperty
(
Details
.
class
)
!=
null
)
si
.
errorMessage
=
Messages
.
HudsonPrivateSecurityRealm_CreateAccount_UserNameAlreadyTaken
();
}
if
(
si
.
fullname
==
null
||
si
.
fullname
.
length
()==
0
)
if
(
si
.
fullname
==
null
||
si
.
fullname
.
length
()
==
0
)
{
si
.
fullname
=
si
.
username
;
}
if
(
isMailerPluginPresent
()
&&
(
si
.
email
==
null
||
!
si
.
email
.
contains
(
"@"
)))
if
(
isMailerPluginPresent
()
&&
(
si
.
email
==
null
||
!
si
.
email
.
contains
(
"@"
)))
{
si
.
errorMessage
=
Messages
.
HudsonPrivateSecurityRealm_CreateAccount_InvalidEmailAddress
();
}
if
(!
User
.
isIdOrFullnameAllowed
(
si
.
username
))
{
if
(!
User
.
isIdOrFullnameAllowed
(
si
.
username
))
{
si
.
errorMessage
=
hudson
.
model
.
Messages
.
User_IllegalUsername
(
si
.
username
);
}
if
(!
User
.
isIdOrFullnameAllowed
(
si
.
fullname
))
{
if
(!
User
.
isIdOrFullnameAllowed
(
si
.
fullname
))
{
si
.
errorMessage
=
hudson
.
model
.
Messages
.
User_IllegalFullname
(
si
.
fullname
);
}
req
.
setAttribute
(
"data"
,
si
);
// for error messages in the view
return
si
;
}
if
(
si
.
errorMessage
!=
null
)
{
// failed. ask the user to try again.
req
.
setAttribute
(
"data"
,
si
);
req
.
getView
(
this
,
formView
).
forward
(
req
,
rsp
);
return
null
;
/**
* Creates a new account from a valid signup info. A signup info is valid if its {@link SignupInfo#errorMessage}
* field is null.
*
* @param si the valid signup info to create an account from
* @return a valid {@link User} object created from given signup info
* @throws IllegalArgumentException if an invalid signup info is passed
*/
private
User
createAccount
(
SignupInfo
si
)
throws
IOException
{
if
(
si
.
errorMessage
!=
null
)
{
throw
new
IllegalArgumentException
(
"invalid signup info passed to createAccount(si): "
+
si
.
errorMessage
);
}
// register the user
User
user
=
createAccount
(
si
.
username
,
si
.
password1
);
User
user
=
createAccount
(
si
.
username
,
si
.
password1
);
user
.
setFullName
(
si
.
fullname
);
if
(
isMailerPluginPresent
())
{
if
(
isMailerPluginPresent
())
{
try
{
// legacy hack. mail support has moved out to a separate plugin
Class
<?>
up
=
Jenkins
.
getInstance
().
pluginManager
.
uberClassLoader
.
loadClass
(
"hudson.tasks.Mailer$UserProperty"
);
Constructor
<?>
c
=
up
.
getDeclaredConstructor
(
String
.
class
);
user
.
addProperty
((
UserProperty
)
c
.
newInstance
(
si
.
email
));
user
.
addProperty
((
UserProperty
)
c
.
newInstance
(
si
.
email
));
}
catch
(
ReflectiveOperationException
e
)
{
throw
new
RuntimeException
(
e
);
}
...
...
@@ -387,7 +444,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
user
.
save
();
return
user
;
}
@Restricted
(
NoExternalUse
.
class
)
public
boolean
isMailerPluginPresent
()
{
try
{
...
...
core/src/main/java/hudson/util/TextFile.java
浏览文件 @
0fd8808b
...
...
@@ -23,25 +23,23 @@
*/
package
hudson.util
;
import
com.google.common.collect.*
;
import
edu.umd.cs.findbugs.annotations.CreatesObligation
;
import
hudson.Util
;
import
jenkins.util.io.LinesStream
;
import
java.nio.file.Files
;
import
java.nio.file.InvalidPathException
;
import
javax.annotation.Nonnull
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileReader
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.io.PrintWriter
;
import
java.io.RandomAccessFile
;
import
java.io.Reader
;
import
java.io.StringWriter
;
import
java.nio.charset.Charset
;
import
java.nio.charset.StandardCharsets
;
import
java.util.Iterator
;
/**
* Represents a text file.
...
...
@@ -51,9 +49,10 @@ import java.util.Iterator;
* @author Kohsuke Kawaguchi
*/
public
class
TextFile
{
public
final
File
file
;
public
TextFile
(
File
file
)
{
public
final
@Nonnull
File
file
;
public
TextFile
(
@Nonnull
File
file
)
{
this
.
file
=
file
;
}
...
...
@@ -82,36 +81,16 @@ public class TextFile {
}
/**
* Parse text file line by line.
* Creates a new {@link jenkins.util.io.LinesStream} of the file.
* <p>
* Note: The caller is responsible for closing the returned
* <code>LinesStream</code>.
* @throws IOException if the file cannot be converted to a
* {@link java.nio.file.Path} or if the file cannot be opened for reading
*/
public
Iterable
<
String
>
lines
()
{
return
new
Iterable
<
String
>()
{
@Override
public
Iterator
<
String
>
iterator
()
{
try
{
final
BufferedReader
in
=
new
BufferedReader
(
new
InputStreamReader
(
Files
.
newInputStream
(
file
.
toPath
()),
"UTF-8"
));
return
new
AbstractIterator
<
String
>()
{
@Override
protected
String
computeNext
()
{
try
{
String
r
=
in
.
readLine
();
if
(
r
==
null
)
{
in
.
close
();
return
endOfData
();
}
return
r
;
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
};
}
catch
(
IOException
|
InvalidPathException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
};
@CreatesObligation
public
@Nonnull
LinesStream
lines
()
throws
IOException
{
return
new
LinesStream
(
Util
.
fileToPath
(
file
));
}
/**
...
...
core/src/main/java/jenkins/install/SetupWizard.java
浏览文件 @
0fd8808b
...
...
@@ -39,6 +39,7 @@ import hudson.model.PageDecorator;
import
hudson.model.UpdateCenter
;
import
hudson.model.UpdateSite
;
import
hudson.model.User
;
import
hudson.security.AccountCreationFailedException
;
import
hudson.security.FullControlOnceLoggedInAuthorizationStrategy
;
import
hudson.security.HudsonPrivateSecurityRealm
;
import
hudson.security.SecurityRealm
;
...
...
@@ -240,49 +241,54 @@ public class SetupWizard extends PageDecorator {
* Called during the initial setup to create an admin user
*/
@RequirePOST
public
HttpResponse
doCreateAdminUser
(
StaplerRequest
req
,
StaplerResponse
rsp
)
throws
IOException
,
ServletException
{
@Restricted
(
NoExternalUse
.
class
)
public
HttpResponse
doCreateAdminUser
(
StaplerRequest
req
,
StaplerResponse
rsp
)
throws
IOException
{
Jenkins
j
=
Jenkins
.
getInstance
();
j
.
checkPermission
(
Jenkins
.
ADMINISTER
);
// This will be set up by default. if not, something changed, ok to fail
HudsonPrivateSecurityRealm
securityRealm
=
(
HudsonPrivateSecurityRealm
)
j
.
getSecurityRealm
();
HudsonPrivateSecurityRealm
securityRealm
=
(
HudsonPrivateSecurityRealm
)
j
.
getSecurityRealm
();
User
admin
=
securityRealm
.
getUser
(
SetupWizard
.
initialSetupAdminUserName
);
try
{
if
(
admin
!=
null
)
{
if
(
admin
!=
null
)
{
admin
.
delete
();
// assume the new user may well be 'admin'
}
User
u
=
securityRealm
.
createAccountByAdmin
(
req
,
rsp
,
"/jenkins/install/SetupWizard/setupWizardFirstUser.jelly"
,
null
);
if
(
u
!=
null
)
{
if
(
admin
!=
null
)
{
admin
=
null
;
}
// Success! Delete the temporary password file:
try
{
getInitialAdminPasswordFile
().
delete
();
}
catch
(
InterruptedException
e
)
{
throw
new
IOException
(
e
);
}
InstallUtil
.
proceedToNextStateFrom
(
InstallState
.
CREATE_ADMIN_USER
);
// ... and then login
Authentication
a
=
new
UsernamePasswordAuthenticationToken
(
u
.
getId
(),
req
.
getParameter
(
"password1"
));
a
=
securityRealm
.
getSecurityComponents
().
manager
.
authenticate
(
a
);
SecurityContextHolder
.
getContext
().
setAuthentication
(
a
);
CrumbIssuer
crumbIssuer
=
Jenkins
.
getInstance
().
getCrumbIssuer
();
JSONObject
data
=
new
JSONObject
();
if
(
crumbIssuer
!=
null
)
{
data
.
accumulate
(
"crumbRequestField"
,
crumbIssuer
.
getCrumbRequestField
()).
accumulate
(
"crumb"
,
crumbIssuer
.
getCrumb
(
req
));
}
return
HttpResponses
.
okJSON
(
data
);
}
else
{
return
HttpResponses
.
okJSON
();
User
newUser
=
securityRealm
.
createAccountFromSetupWizard
(
req
);
if
(
admin
!=
null
)
{
admin
=
null
;
}
// Success! Delete the temporary password file:
try
{
getInitialAdminPasswordFile
().
delete
();
}
catch
(
InterruptedException
e
)
{
throw
new
IOException
(
e
);
}
InstallUtil
.
proceedToNextStateFrom
(
InstallState
.
CREATE_ADMIN_USER
);
// ... and then login
Authentication
auth
=
new
UsernamePasswordAuthenticationToken
(
newUser
.
getId
(),
req
.
getParameter
(
"password1"
));
auth
=
securityRealm
.
getSecurityComponents
().
manager
.
authenticate
(
auth
);
SecurityContextHolder
.
getContext
().
setAuthentication
(
auth
);
CrumbIssuer
crumbIssuer
=
Jenkins
.
getInstance
().
getCrumbIssuer
();
JSONObject
data
=
new
JSONObject
();
if
(
crumbIssuer
!=
null
)
{
data
.
accumulate
(
"crumbRequestField"
,
crumbIssuer
.
getCrumbRequestField
()).
accumulate
(
"crumb"
,
crumbIssuer
.
getCrumb
(
req
));
}
return
HttpResponses
.
okJSON
(
data
);
}
catch
(
AccountCreationFailedException
e
)
{
/*
Return Unprocessable Entity from WebDAV. While this is not technically in the HTTP/1.1 standard, browsers
seem to accept this. 400 Bad Request is technically inappropriate because that implies invalid *syntax*,
not incorrect data. The client only cares about it being >200 anyways.
*/
rsp
.
setStatus
(
422
);
return
HttpResponses
.
forwardToView
(
securityRealm
,
"/jenkins/install/SetupWizard/setupWizardFirstUser.jelly"
);
}
finally
{
if
(
admin
!=
null
)
{
if
(
admin
!=
null
)
{
admin
.
save
();
// recreate this initial user if something failed
}
}
...
...
core/src/main/java/jenkins/security/s2m/ConfigFile.java
浏览文件 @
0fd8808b
...
...
@@ -3,6 +3,7 @@ package jenkins.security.s2m;
import
hudson.CopyOnWrite
;
import
hudson.util.TextFile
;
import
jenkins.model.Jenkins
;
import
jenkins.util.io.LinesStream
;
import
java.io.BufferedReader
;
import
java.io.File
;
...
...
@@ -26,15 +27,42 @@ abstract class ConfigFile<T,COL extends Collection<T>> extends TextFile {
protected
abstract
COL
create
();
protected
abstract
COL
readOnly
(
COL
base
);
public
synchronized
void
load
()
{
/**
* Loads the configuration from the configuration file.
* <p>
* This method is equivalent to {@link #load2()}, except that any
* {@link java.io.IOException} that occurs is wrapped as a
* {@link java.lang.RuntimeException}.
* <p>
* This method exists for source compatibility. Users should call
* {@link #load2()} instead.
* @deprecated use {@link #load2()} instead.
*/
@Deprecated
public
void
load
()
{
try
{
load2
();
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
/**
* Loads the configuration from the configuration file.
* @throws IOException if the configuration file could not be read.
* @since TODO
*/
public
synchronized
void
load2
()
throws
IOException
{
COL
result
=
create
();
if
(
exists
())
{
for
(
String
line
:
lines
())
{
if
(
line
.
startsWith
(
"#"
))
continue
;
// comment
T
r
=
parse
(
line
);
if
(
r
!=
null
)
result
.
add
(
r
);
try
(
LinesStream
stream
=
lines
())
{
for
(
String
line
:
stream
)
{
if
(
line
.
startsWith
(
"#"
))
continue
;
// comment
T
r
=
parse
(
line
);
if
(
r
!=
null
)
result
.
add
(
r
);
}
}
}
...
...
@@ -63,7 +91,7 @@ abstract class ConfigFile<T,COL extends Collection<T>> extends TextFile {
Jenkins
.
getInstance
().
checkPermission
(
Jenkins
.
ADMINISTER
);
write
(
newContent
);
load
();
load
2
();
}
public
synchronized
void
append
(
String
additional
)
throws
IOException
{
...
...
@@ -79,8 +107,9 @@ abstract class ConfigFile<T,COL extends Collection<T>> extends TextFile {
// load upon the first use
if
(
parsed
==
null
)
{
synchronized
(
this
)
{
if
(
parsed
==
null
)
if
(
parsed
==
null
)
{
load
();
}
}
}
return
parsed
;
...
...
core/src/main/java/jenkins/util/io/LinesStream.java
0 → 100644
浏览文件 @
0fd8808b
/*
* The MIT License
*
* Copyright 2018 Daniel Trebbien.
*
* 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.io
;
import
com.google.common.collect.AbstractIterator
;
import
edu.umd.cs.findbugs.annotations.CleanupObligation
;
import
edu.umd.cs.findbugs.annotations.DischargesObligation
;
import
java.io.BufferedReader
;
import
java.io.Closeable
;
import
java.io.IOException
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.util.Iterator
;
import
javax.annotation.Nonnull
;
import
javax.annotation.Nullable
;
/**
* Represents a stream over the lines of a text file.
* <p>
* Although <code>LinesStream</code> implements {@link java.lang.Iterable}, it
* is intended to be first used to initialize a resource in a try-with-resources
* statement and then iterated, as in:
* <pre>
* try (LinesStream stream = new LinesStream(...)) {
* for (String line : stream) {
* ...
* }
* }
* </pre>
* This pattern ensures that the underlying file handle is closed properly.
* <p>
* Like {@link java.nio.file.DirectoryStream}, <code>LinesStream</code> supports
* creating at most one <code>Iterator</code>. Invoking {@link #iterator()} to
* obtain a second or subsequent <code>Iterator</code> throws
* <code>IllegalStateException</code>.
*
* @since TODO
*/
@CleanupObligation
public
class
LinesStream
implements
Closeable
,
Iterable
<
String
>
{
private
final
@Nonnull
BufferedReader
in
;
private
transient
@Nullable
Iterator
<
String
>
iterator
;
/**
* Opens the text file at <code>path</code> for reading using charset
* {@link java.nio.charset.StandardCharsets#UTF_8}.
* @param path Path to the file to open for reading.
* @throws IOException if the file at <code>path</code> cannot be opened for
* reading.
*/
public
LinesStream
(
@Nonnull
Path
path
)
throws
IOException
{
in
=
Files
.
newBufferedReader
(
path
);
// uses UTF-8 by default
}
@DischargesObligation
@Override
public
void
close
()
throws
IOException
{
in
.
close
();
}
@Override
public
Iterator
<
String
>
iterator
()
{
if
(
iterator
!=
null
)
throw
new
IllegalStateException
(
"Only one Iterator can be created."
);
iterator
=
new
AbstractIterator
<
String
>()
{
@Override
protected
String
computeNext
()
{
try
{
String
r
=
in
.
readLine
();
if
(
r
==
null
)
{
// Calling close() here helps ensure that the file
// handle is closed even when LinesStream is being used
// incorrectly, where it is iterated over without being
// used to initialize a resource of a try-with-resources
// statement.
in
.
close
();
return
endOfData
();
}
return
r
;
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
};
return
iterator
;
}
}
pom.xml
浏览文件 @
0fd8808b
...
...
@@ -28,7 +28,7 @@ THE SOFTWARE.
<parent>
<groupId>
org.jenkins-ci
</groupId>
<artifactId>
jenkins
</artifactId>
<version>
1.
39
</version>
<version>
1.
40
</version>
</parent>
<groupId>
org.jenkins-ci.main
</groupId>
...
...
@@ -92,8 +92,6 @@ THE SOFTWARE.
<matrix-project.version>
1.4.1
</matrix-project.version>
<sorcerer.version>
0.11
</sorcerer.version>
<animal.sniffer.skip>
${skipTests}
</animal.sniffer.skip>
<findbugs-maven-plugin.version>
3.0.4
</findbugs-maven-plugin.version>
<findbugs.failOnError>
true
</findbugs.failOnError>
<access-modifier.version>
1.13
</access-modifier.version>
<access-modifier-annotation.version>
${access-modifier.version}
</access-modifier-annotation.version>
<!-- differing only where needed for timestamped snapshots -->
<access-modifier-checker.version>
${access-modifier.version}
</access-modifier-checker.version>
...
...
@@ -108,6 +106,9 @@ THE SOFTWARE.
<remoting.version>
3.17
</remoting.version>
<remoting.minimum.supported.version>
2.60
</remoting.minimum.supported.version>
<findbugs.effort>
Max
</findbugs.effort>
<findbugs.threshold>
High
</findbugs.threshold>
<findbugs.excludeFilterFile>
../src/findbugs/findbugs-excludes.xml
</findbugs.excludeFilterFile>
</properties>
<!-- Note that the 'repositories' and 'pluginRepositories' blocks below are actually copy-pasted
...
...
@@ -492,28 +493,6 @@ THE SOFTWARE.
<artifactId>
antlr-maven-plugin
</artifactId>
<version>
2.1
</version>
</plugin>
<plugin>
<groupId>
org.codehaus.mojo
</groupId>
<artifactId>
findbugs-maven-plugin
</artifactId>
<version>
${findbugs-maven-plugin.version}
</version>
<configuration>
<effort>
Max
</effort>
<threshold>
High
</threshold>
<!--Excludes file is located on the top level-->
<excludeFilterFile>
../src/findbugs/findbugs-excludes.xml
</excludeFilterFile>
<xmlOutput>
true
</xmlOutput>
<findbugsXmlOutput>
false
</findbugsXmlOutput>
</configuration>
<executions>
<execution>
<id>
findbugs
</id>
<goals>
<goal>
check
</goal>
</goals>
<phase>
verify
</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-pmd-plugin
</artifactId>
...
...
war/src/main/js/pluginSetupWizardGui.js
浏览文件 @
0fd8808b
...
...
@@ -872,45 +872,37 @@ var createPluginSetupWizard = function(appendTarget) {
$c
.
slideDown
();
}
};
var
handleStaplerSubmit
=
function
(
data
)
{
if
(
data
.
status
&&
data
.
status
>
200
)
{
// Nothing we can really do here
setPanel
(
errorPanel
,
{
errorMessage
:
data
.
statusText
});
return
;
}
try
{
if
(
JSON
.
parse
(
data
).
status
===
'
ok
'
)
{
showStatePanel
();
return
;
}
}
catch
(
e
)
{
// ignore JSON parsing issues, this may be HTML
var
handleFirstUserResponseSuccess
=
function
(
data
)
{
if
(
data
.
status
===
'
ok
'
)
{
showStatePanel
();
}
else
{
setPanel
(
errorPanel
,
{
errorMessage
:
'
Error trying to create first user:
'
+
data
.
statusText
});
}
// we get 200 OK
var
responseText
=
data
.
responseText
;
};
var
handleFirstUserResponseError
=
function
(
res
)
{
// We're expecting a full HTML page to replace the form
// We can only replace the _whole_ iframe due to XSS rules
// https://stackoverflow.com/a/22913801/1117552
var
responseText
=
res
.
responseText
;
var
$page
=
$
(
responseText
);
var
$errors
=
$page
.
find
(
'
.error
'
);
if
(
$errors
.
length
>
0
)
{
var
$main
=
$page
.
find
(
'
#main-panel
'
).
detach
();
if
(
$main
.
length
>
0
)
{
responseText
=
responseText
.
replace
(
/body
([^
>
]
*
)[
>
](
.|
[\r\n])
+
[
<
][/]
body/
,
'
body$1>
'
+
$main
.
html
()
+
'
</body
'
);
}
var
doc
=
$
(
'
iframe[src]
'
).
contents
()[
0
];
doc
.
open
();
doc
.
write
(
responseText
);
doc
.
close
();
}
else
{
showStatePanel
();
var
$main
=
$page
.
find
(
'
#main-panel
'
).
detach
();
if
(
$main
.
length
>
0
)
{
responseText
=
responseText
.
replace
(
/body
([^
>
]
*
)[
>
](
.|
[\r\n])
+
[
<
][/]
body/
,
'
body$1>
'
+
$main
.
html
()
+
'
</body
'
);
}
var
doc
=
$
(
'
iframe#setup-first-user
'
).
contents
()[
0
];
doc
.
open
();
doc
.
write
(
responseText
);
doc
.
close
();
$
(
'
button
'
).
prop
({
disabled
:
false
});
};
// call to submit the firstuser
var
saveFirstUser
=
function
()
{
$
(
'
button
'
).
prop
({
disabled
:
true
});
securityConfig
.
saveFirstUser
(
$
(
'
iframe[src]
'
).
contents
().
find
(
'
form:not(.no-json)
'
),
handleStaplerSubmit
,
handleStaplerSubmit
);
var
$form
=
$
(
'
iframe#setup-first-user
'
).
contents
().
find
(
'
form:not(.no-json)
'
);
securityConfig
.
saveFirstUser
(
$form
,
handleFirstUserResponseSuccess
,
handleFirstUserResponseError
);
};
var
skipFirstUser
=
function
()
{
...
...
war/src/main/js/templates/firstUserPanel.hbs
浏览文件 @
0fd8808b
...
...
@@ -3,7 +3,7 @@
</div>
<div
class=
"modal-body"
>
<div
class=
"jumbotron welcome-panel security-panel"
>
<iframe
src=
"
{{
baseUrl
}}
/setupWizard/setupWizardFirstUser"
></iframe>
<iframe
src=
"
{{
baseUrl
}}
/setupWizard/setupWizardFirstUser"
id=
"setup-first-user"
></iframe>
</div>
</div>
<div
class=
"modal-footer"
>
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录