Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
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
DEMO
spring-boot
Commits
a20fdf8e
Commit
a20fdf8e
authored
Sep 14, 2020
by
Phillip Webb
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '2.1.x' into 2.2.x
Closes gh-23263
parents
326a56da
895ff9c7
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
149 additions
and
63 deletions
+149
-63
.gitignore
.gitignore
+2
-1
JarEntry.java
...in/java/org/springframework/boot/loader/jar/JarEntry.java
+23
-17
JarEntryCertification.java
...pringframework/boot/loader/jar/JarEntryCertification.java
+58
-0
JarFile.java
...ain/java/org/springframework/boot/loader/jar/JarFile.java
+2
-21
JarFileEntries.java
...a/org/springframework/boot/loader/jar/JarFileEntries.java
+40
-5
JarFileTests.java
...ava/org/springframework/boot/loader/jar/JarFileTests.java
+24
-19
No files found.
.gitignore
View file @
a20fdf8e
...
...
@@ -19,6 +19,7 @@
.settings
.springBeans
/build
.vscode
/code
MANIFEST.MF
_site/
...
...
@@ -38,4 +39,4 @@ transaction-logs
secrets.yml
.gradletasknamecache
.sts4-cache
.mvn/.gradle-enterprise/gradle-enterprise-workspace-id
\ No newline at end of file
.mvn/.gradle-enterprise/gradle-enterprise-workspace-id
spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntry.java
View file @
a20fdf8e
/*
* Copyright 2012-20
19
the original author or authors.
* Copyright 2012-20
20
the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
...
...
@@ -32,20 +32,21 @@ import java.util.jar.Manifest;
*/
class
JarEntry
extends
java
.
util
.
jar
.
JarEntry
implements
FileHeader
{
private
final
int
index
;
private
final
AsciiBytes
name
;
private
final
AsciiBytes
headerName
;
private
Certificate
[]
certificates
;
private
CodeSigner
[]
codeSigners
;
private
final
JarFile
jarFile
;
private
long
localHeaderOffset
;
JarEntry
(
JarFile
jarFile
,
CentralDirectoryFileHeader
header
,
AsciiBytes
nameAlias
)
{
private
volatile
JarEntryCertification
certification
;
JarEntry
(
JarFile
jarFile
,
int
index
,
CentralDirectoryFileHeader
header
,
AsciiBytes
nameAlias
)
{
super
((
nameAlias
!=
null
)
?
nameAlias
.
toString
()
:
header
.
getName
().
toString
());
this
.
index
=
index
;
this
.
name
=
(
nameAlias
!=
null
)
?
nameAlias
:
header
.
getName
();
this
.
headerName
=
header
.
getName
();
this
.
jarFile
=
jarFile
;
...
...
@@ -61,6 +62,10 @@ class JarEntry extends java.util.jar.JarEntry implements FileHeader {
}
}
int
getIndex
()
{
return
this
.
index
;
}
AsciiBytes
getAsciiBytesName
()
{
return
this
.
name
;
}
...
...
@@ -87,23 +92,24 @@ class JarEntry extends java.util.jar.JarEntry implements FileHeader {
@Override
public
Certificate
[]
getCertificates
()
{
if
(
this
.
jarFile
.
isSigned
()
&&
this
.
certificates
==
null
)
{
this
.
jarFile
.
setupEntryCertificates
(
this
);
}
return
this
.
certificates
;
return
getCertification
().
getCertificates
();
}
@Override
public
CodeSigner
[]
getCodeSigners
()
{
if
(
this
.
jarFile
.
isSigned
()
&&
this
.
codeSigners
==
null
)
{
this
.
jarFile
.
setupEntryCertificates
(
this
);
}
return
this
.
codeSigners
;
return
getCertification
().
getCodeSigners
();
}
void
setCertificates
(
java
.
util
.
jar
.
JarEntry
entry
)
{
this
.
certificates
=
entry
.
getCertificates
();
this
.
codeSigners
=
entry
.
getCodeSigners
();
private
JarEntryCertification
getCertification
()
{
if
(!
this
.
jarFile
.
isSigned
())
{
return
JarEntryCertification
.
NONE
;
}
JarEntryCertification
certification
=
this
.
certification
;
if
(
certification
==
null
)
{
certification
=
this
.
jarFile
.
getCertification
(
this
);
this
.
certification
=
certification
;
}
return
certification
;
}
@Override
...
...
spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryCertification.java
0 → 100644
View file @
a20fdf8e
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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
.
springframework
.
boot
.
loader
.
jar
;
import
java.security.CodeSigner
;
import
java.security.cert.Certificate
;
/**
* {@link Certificate} and {@link CodeSigner} details for a {@link JarEntry} from a signed
* {@link JarFile}.
*
* @author Phillip Webb
*/
class
JarEntryCertification
{
static
final
JarEntryCertification
NONE
=
new
JarEntryCertification
(
null
,
null
);
private
final
Certificate
[]
certificates
;
private
final
CodeSigner
[]
codeSigners
;
JarEntryCertification
(
Certificate
[]
certificates
,
CodeSigner
[]
codeSigners
)
{
this
.
certificates
=
certificates
;
this
.
codeSigners
=
codeSigners
;
}
Certificate
[]
getCertificates
()
{
return
(
this
.
certificates
!=
null
)
?
this
.
certificates
.
clone
()
:
null
;
}
CodeSigner
[]
getCodeSigners
()
{
return
(
this
.
codeSigners
!=
null
)
?
this
.
codeSigners
.
clone
()
:
null
;
}
static
JarEntryCertification
from
(
java
.
util
.
jar
.
JarEntry
certifiedEntry
)
{
Certificate
[]
certificates
=
(
certifiedEntry
!=
null
)
?
certifiedEntry
.
getCertificates
()
:
null
;
CodeSigner
[]
codeSigners
=
(
certifiedEntry
!=
null
)
?
certifiedEntry
.
getCodeSigners
()
:
null
;
if
(
certificates
==
null
&&
codeSigners
==
null
)
{
return
NONE
;
}
return
new
JarEntryCertification
(
certificates
,
codeSigners
);
}
}
spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java
View file @
a20fdf8e
...
...
@@ -29,7 +29,6 @@ import java.security.Permission;
import
java.util.Enumeration
;
import
java.util.Iterator
;
import
java.util.function.Supplier
;
import
java.util.jar.JarInputStream
;
import
java.util.jar.Manifest
;
import
java.util.zip.ZipEntry
;
...
...
@@ -353,33 +352,15 @@ public class JarFile extends AbstractJarFile {
return
this
.
signed
;
}
void
setupEntryCertificates
(
JarEntry
entry
)
{
// Fallback to JarInputStream to obtain certificates, not fast but hopefully not
// happening that often.
JarEntryCertification
getCertification
(
JarEntry
entry
)
{
try
{
try
(
JarInputStream
inputStream
=
new
JarInputStream
(
getData
().
getInputStream
()))
{
java
.
util
.
jar
.
JarEntry
certEntry
=
inputStream
.
getNextJarEntry
();
while
(
certEntry
!=
null
)
{
inputStream
.
closeEntry
();
if
(
entry
.
getName
().
equals
(
certEntry
.
getName
()))
{
setCertificates
(
entry
,
certEntry
);
}
setCertificates
(
getJarEntry
(
certEntry
.
getName
()),
certEntry
);
certEntry
=
inputStream
.
getNextJarEntry
();
}
}
return
this
.
entries
.
getCertification
(
entry
);
}
catch
(
IOException
ex
)
{
throw
new
IllegalStateException
(
ex
);
}
}
private
void
setCertificates
(
JarEntry
entry
,
java
.
util
.
jar
.
JarEntry
certEntry
)
{
if
(
entry
!=
null
)
{
entry
.
setCertificates
(
certEntry
);
}
}
public
void
clearCache
()
{
this
.
entries
.
clearCache
();
}
...
...
spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFileEntries.java
View file @
a20fdf8e
/*
* Copyright 2012-20
19
the original author or authors.
* Copyright 2012-20
20
the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
...
...
@@ -26,6 +26,7 @@ import java.util.Map;
import
java.util.NoSuchElementException
;
import
java.util.jar.Attributes
;
import
java.util.jar.Attributes.Name
;
import
java.util.jar.JarInputStream
;
import
java.util.jar.Manifest
;
import
java.util.zip.ZipEntry
;
...
...
@@ -91,14 +92,13 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> {
private
Boolean
multiReleaseJar
;
private
JarEntryCertification
[]
certifications
;
private
final
Map
<
Integer
,
FileHeader
>
entriesCache
=
Collections
.
synchronizedMap
(
new
LinkedHashMap
<
Integer
,
FileHeader
>(
16
,
0.75f
,
true
)
{
@Override
protected
boolean
removeEldestEntry
(
Map
.
Entry
<
Integer
,
FileHeader
>
eldest
)
{
if
(
JarFileEntries
.
this
.
jarFile
.
isSigned
())
{
return
false
;
}
return
size
()
>=
ENTRY_CACHE_SIZE
;
}
...
...
@@ -313,7 +313,7 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> {
FileHeader
entry
=
(
cached
!=
null
)
?
cached
:
CentralDirectoryFileHeader
.
fromRandomAccessData
(
this
.
centralDirectoryData
,
this
.
centralDirectoryOffsets
[
index
],
this
.
filter
);
if
(
CentralDirectoryFileHeader
.
class
.
equals
(
entry
.
getClass
())
&&
type
.
equals
(
JarEntry
.
class
))
{
entry
=
new
JarEntry
(
this
.
jarFile
,
(
CentralDirectoryFileHeader
)
entry
,
nameAlias
);
entry
=
new
JarEntry
(
this
.
jarFile
,
index
,
(
CentralDirectoryFileHeader
)
entry
,
nameAlias
);
}
if
(
cacheEntry
&&
cached
!=
entry
)
{
this
.
entriesCache
.
put
(
index
,
entry
);
...
...
@@ -344,6 +344,41 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> {
return
(
this
.
filter
!=
null
)
?
this
.
filter
.
apply
(
name
)
:
name
;
}
JarEntryCertification
getCertification
(
JarEntry
entry
)
throws
IOException
{
JarEntryCertification
[]
certifications
=
this
.
certifications
;
if
(
certifications
==
null
)
{
certifications
=
new
JarEntryCertification
[
this
.
size
];
// We fallback to use JarInputStream to obtain the certs. This isn't that
// fast, but hopefully doesn't happen too often.
try
(
JarInputStream
certifiedJarStream
=
new
JarInputStream
(
this
.
jarFile
.
getData
().
getInputStream
()))
{
java
.
util
.
jar
.
JarEntry
certifiedEntry
=
null
;
while
((
certifiedEntry
=
certifiedJarStream
.
getNextJarEntry
())
!=
null
)
{
int
index
=
getEntryIndex
(
certifiedEntry
.
getName
());
if
(
index
!=
-
1
)
{
certifications
[
index
]
=
JarEntryCertification
.
from
(
certifiedEntry
);
}
certifiedJarStream
.
closeEntry
();
}
}
this
.
certifications
=
certifications
;
}
JarEntryCertification
certification
=
certifications
[
entry
.
getIndex
()];
return
(
certification
!=
null
)
?
certification
:
JarEntryCertification
.
NONE
;
}
private
int
getEntryIndex
(
CharSequence
name
)
{
int
hashCode
=
AsciiBytes
.
hashCode
(
name
);
int
index
=
getFirstIndex
(
hashCode
);
while
(
index
>=
0
&&
index
<
this
.
size
&&
this
.
hashCodes
[
index
]
==
hashCode
)
{
CentralDirectoryFileHeader
candidate
=
getEntry
(
index
,
CentralDirectoryFileHeader
.
class
,
false
,
null
);
if
(
candidate
.
hasName
(
name
,
NO_SUFFIX
))
{
return
index
;
}
index
++;
}
return
-
1
;
}
/**
* Iterator for contained entries.
*/
...
...
spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java
View file @
a20fdf8e
...
...
@@ -51,6 +51,7 @@ import org.springframework.boot.loader.TestJarCreator;
import
org.springframework.boot.loader.data.RandomAccessDataFile
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
org.springframework.util.FileCopyUtils
;
import
org.springframework.util.StopWatch
;
import
org.springframework.util.StreamUtils
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
...
...
@@ -397,29 +398,33 @@ class JarFileTests {
@Test
void
verifySignedJar
()
throws
Exception
{
String
classpath
=
System
.
getProperty
(
"java.class.path"
);
String
[]
entries
=
classpath
.
split
(
System
.
getProperty
(
"path.separator"
));
String
signedJarFile
=
null
;
for
(
String
entry
:
entries
)
{
if
(
entry
.
contains
(
"bcprov"
))
{
signedJarFile
=
entry
;
File
signedJarFile
=
getSignedJarFile
();
assertThat
(
signedJarFile
).
exists
();
try
(
java
.
util
.
jar
.
JarFile
expected
=
new
java
.
util
.
jar
.
JarFile
(
signedJarFile
))
{
try
(
JarFile
actual
=
new
JarFile
(
signedJarFile
))
{
StopWatch
stopWatch
=
new
StopWatch
();
Enumeration
<
JarEntry
>
actualEntries
=
actual
.
entries
();
while
(
actualEntries
.
hasMoreElements
())
{
JarEntry
actualEntry
=
actualEntries
.
nextElement
();
java
.
util
.
jar
.
JarEntry
expectedEntry
=
expected
.
getJarEntry
(
actualEntry
.
getName
());
assertThat
(
actualEntry
.
getCertificates
()).
as
(
actualEntry
.
getName
())
.
isEqualTo
(
expectedEntry
.
getCertificates
());
assertThat
(
actualEntry
.
getCodeSigners
()).
as
(
actualEntry
.
getName
())
.
isEqualTo
(
expectedEntry
.
getCodeSigners
());
}
assertThat
(
stopWatch
.
getTotalTimeSeconds
()).
isLessThan
(
3.0
);
}
}
assertThat
(
signedJarFile
).
isNotNull
();
java
.
util
.
jar
.
JarFile
jarFile
=
new
JarFile
(
new
File
(
signedJarFile
));
jarFile
.
getManifest
();
Enumeration
<
JarEntry
>
jarEntries
=
jarFile
.
entries
();
while
(
jarEntries
.
hasMoreElements
())
{
JarEntry
jarEntry
=
jarEntries
.
nextElement
();
InputStream
inputStream
=
jarFile
.
getInputStream
(
jarEntry
);
inputStream
.
skip
(
Long
.
MAX_VALUE
);
inputStream
.
close
();
if
(!
jarEntry
.
getName
().
startsWith
(
"META-INF"
)
&&
!
jarEntry
.
isDirectory
()
&&
!
jarEntry
.
getName
().
endsWith
(
"TigerDigest.class"
))
{
assertThat
(
jarEntry
.
getCertificates
()).
isNotNull
();
}
private
File
getSignedJarFile
()
{
String
[]
entries
=
System
.
getProperty
(
"java.class.path"
).
split
(
System
.
getProperty
(
"path.separator"
));
for
(
String
entry
:
entries
)
{
if
(
entry
.
contains
(
"bcprov"
))
{
return
new
File
(
entry
);
}
}
jarFile
.
close
()
;
return
null
;
}
@Test
...
...
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