From 0486111572bec4f9da5619360c551698f32e6269 Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Sun, 7 Nov 2021 17:18:14 -0800 Subject: [PATCH 01/15] Draft for review of security for plugin developers --- content/doc/book/security/_chapter.yml | 4 ++ .../doc/book/security/plugin-developer.adoc | 41 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 content/doc/book/security/plugin-developer.adoc diff --git a/content/doc/book/security/_chapter.yml b/content/doc/book/security/_chapter.yml index f7a36d799c28..7beca6218220 100644 --- a/content/doc/book/security/_chapter.yml +++ b/content/doc/book/security/_chapter.yml @@ -18,3 +18,7 @@ sections: # Further references - services + +- controller-isolation/required-role-check +- plugin-developer + diff --git a/content/doc/book/security/plugin-developer.adoc b/content/doc/book/security/plugin-developer.adoc new file mode 100644 index 000000000000..ed99aa14f63b --- /dev/null +++ b/content/doc/book/security/plugin-developer.adoc @@ -0,0 +1,41 @@ +--- +title: Security for Plugin Developers +layout: section +--- +ifdef::backend-html5[] +:toc: +ifdef::env-github[:imagesdir: ../resources] +ifndef::env-github[:imagesdir: ../../resources] +:hide-uri-scheme: +endif::[] + +Developers and maintainers of plugins play a crucial role in maintaining Jenkins security. +This page summarizes the security practices required. + +== Monitor Security Advisories + +Monitor Jenkins +link:https://www.jenkins.io/security/advisories/[Security Advisories] +closely. +It may be necessary to modify your plugin to work and comply with security fixes. + +== Script Security + +Be sure that your plugin implements appropriate security +for custom Groovy scripts that users may need to create to customize Jenkins. + +For more information, see the _Developer's Guide_ section of the +link:https://plugins.jenkins.io/script-security/[Script Security] documentation. + +== Provide Role Check for Callable + +Communication between the Jenkins controller and agents is implemented with the Java +link:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Callable.html[Callable] interface. +Plugins should always implement a _role check_ that runs after a +`Callable` message to ensure that the object executes on the proper side of the controller-agent communication. +Jenkins 2.319 and Jenkins LTS 2.303.3 and later releases enforce this behavior. +A plugin that does not comply throws a `SecurityException` and logs an error message. + +See +link:http://localhost:4242/doc/book/security/controller-isolation/required-role-check/[Required Role Check] +for more information. From 6a6061f7bd5e9a99d79829d4e8d9236635664725 Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Tue, 9 Nov 2021 01:46:20 -0800 Subject: [PATCH 02/15] Add info about protecting secrets --- content/doc/book/security/plugin-developer.adoc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/content/doc/book/security/plugin-developer.adoc b/content/doc/book/security/plugin-developer.adoc index ed99aa14f63b..cb66a1821702 100644 --- a/content/doc/book/security/plugin-developer.adoc +++ b/content/doc/book/security/plugin-developer.adoc @@ -19,6 +19,18 @@ link:https://www.jenkins.io/security/advisories/[Security Advisories] closely. It may be necessary to modify your plugin to work and comply with security fixes. +== Store User Credentials as Secrets + +Protect user credentials by storing them on disk in a field of type `Secret` +and never in a simple `String` field. +Protect user credentials by storing them on disk in a field of type `Secret` +and never in a simple `String` field. +Use a getter that returns the same type to access the `Secrets` field +from other code. +See +link:https://www.jenkins.io/doc/developer/security/secrets/[Storing Secrets] +for background information, instructions, and code examples. + == Script Security Be sure that your plugin implements appropriate security From 81aea4b22b90a7ded40c05decad1dbdd084d3df7 Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Wed, 10 Nov 2021 04:02:11 -0800 Subject: [PATCH 03/15] delete duplicate line --- content/doc/book/security/plugin-developer.adoc | 1 - 1 file changed, 1 deletion(-) diff --git a/content/doc/book/security/plugin-developer.adoc b/content/doc/book/security/plugin-developer.adoc index cb66a1821702..836a1f0f4740 100644 --- a/content/doc/book/security/plugin-developer.adoc +++ b/content/doc/book/security/plugin-developer.adoc @@ -23,7 +23,6 @@ It may be necessary to modify your plugin to work and comply with security fixes Protect user credentials by storing them on disk in a field of type `Secret` and never in a simple `String` field. -Protect user credentials by storing them on disk in a field of type `Secret` and never in a simple `String` field. Use a getter that returns the same type to access the `Secrets` field from other code. From 7e928d40d81342ee0ec915a011f36adba5d0acb8 Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Wed, 10 Nov 2021 04:03:34 -0800 Subject: [PATCH 04/15] delete duplicate line --- content/doc/book/security/plugin-developer.adoc | 1 - 1 file changed, 1 deletion(-) diff --git a/content/doc/book/security/plugin-developer.adoc b/content/doc/book/security/plugin-developer.adoc index 836a1f0f4740..3cda58377dd5 100644 --- a/content/doc/book/security/plugin-developer.adoc +++ b/content/doc/book/security/plugin-developer.adoc @@ -23,7 +23,6 @@ It may be necessary to modify your plugin to work and comply with security fixes Protect user credentials by storing them on disk in a field of type `Secret` and never in a simple `String` field. -and never in a simple `String` field. Use a getter that returns the same type to access the `Secrets` field from other code. See From 3a1e354ba01fd3d2295d2124c71828fd618f7af4 Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Wed, 10 Nov 2021 19:31:53 -0800 Subject: [PATCH 05/15] Move security-for-plugin-developers to /doc/developer --- content/doc/book/security/_chapter.yml | 1 - .../doc/book/security/plugin-developer.adoc | 53 ----- content/doc/developer/security/_chapter.yml | 1 + content/doc/developer/security/index.adoc | 193 ++++-------------- .../security/security-architecture.adoc | 182 +++++++++++++++++ 5 files changed, 222 insertions(+), 208 deletions(-) delete mode 100644 content/doc/book/security/plugin-developer.adoc create mode 100644 content/doc/developer/security/security-architecture.adoc diff --git a/content/doc/book/security/_chapter.yml b/content/doc/book/security/_chapter.yml index 7beca6218220..f0f8ba755d26 100644 --- a/content/doc/book/security/_chapter.yml +++ b/content/doc/book/security/_chapter.yml @@ -20,5 +20,4 @@ sections: - services - controller-isolation/required-role-check -- plugin-developer diff --git a/content/doc/book/security/plugin-developer.adoc b/content/doc/book/security/plugin-developer.adoc deleted file mode 100644 index cb66a1821702..000000000000 --- a/content/doc/book/security/plugin-developer.adoc +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Security for Plugin Developers -layout: section ---- -ifdef::backend-html5[] -:toc: -ifdef::env-github[:imagesdir: ../resources] -ifndef::env-github[:imagesdir: ../../resources] -:hide-uri-scheme: -endif::[] - -Developers and maintainers of plugins play a crucial role in maintaining Jenkins security. -This page summarizes the security practices required. - -== Monitor Security Advisories - -Monitor Jenkins -link:https://www.jenkins.io/security/advisories/[Security Advisories] -closely. -It may be necessary to modify your plugin to work and comply with security fixes. - -== Store User Credentials as Secrets - -Protect user credentials by storing them on disk in a field of type `Secret` -and never in a simple `String` field. -Protect user credentials by storing them on disk in a field of type `Secret` -and never in a simple `String` field. -Use a getter that returns the same type to access the `Secrets` field -from other code. -See -link:https://www.jenkins.io/doc/developer/security/secrets/[Storing Secrets] -for background information, instructions, and code examples. - -== Script Security - -Be sure that your plugin implements appropriate security -for custom Groovy scripts that users may need to create to customize Jenkins. - -For more information, see the _Developer's Guide_ section of the -link:https://plugins.jenkins.io/script-security/[Script Security] documentation. - -== Provide Role Check for Callable - -Communication between the Jenkins controller and agents is implemented with the Java -link:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Callable.html[Callable] interface. -Plugins should always implement a _role check_ that runs after a -`Callable` message to ensure that the object executes on the proper side of the controller-agent communication. -Jenkins 2.319 and Jenkins LTS 2.303.3 and later releases enforce this behavior. -A plugin that does not comply throws a `SecurityException` and logs an error message. - -See -link:http://localhost:4242/doc/book/security/controller-isolation/required-role-check/[Required Role Check] -for more information. diff --git a/content/doc/developer/security/_chapter.yml b/content/doc/developer/security/_chapter.yml index b6cdbc5647fe..46575c64600c 100644 --- a/content/doc/developer/security/_chapter.yml +++ b/content/doc/developer/security/_chapter.yml @@ -1,5 +1,6 @@ --- sections: +- security-architecture - secrets guides: - form-validation diff --git a/content/doc/developer/security/index.adoc b/content/doc/developer/security/index.adoc index 7f737e73b1e6..41ab0861232f 100644 --- a/content/doc/developer/security/index.adoc +++ b/content/doc/developer/security/index.adoc @@ -7,175 +7,60 @@ references: title: Script Security Developer's Guide --- -:imagesdir: /doc/developer/security/resources +Developers and maintainers of plugins play a crucial role in maintaining Jenkins security. +This chapter discusses the security practices required. -// this is a straight import of https://wiki.jenkins.io/display/JENKINS/Making+your+plugin+behave+in+secured+Jenkins -// TODO check contents and remove wiki page +Monitor security advisories:: +Monitor Jenkins +link:https://www.jenkins.io/security/advisories/[Security Advisories] +closely. +It may be necessary to modify your plugin to work and comply with security fixes. -== Security Architecture of Jenkins +Conform to access permissions:: -Jenkins has a security mechanism in place so that the administrator of Jenkins can control who gets access to what part of Jenkins. -The key components of this mechanism are the followings: +Understand and conform to the +link:http://localhost:4242/doc/developer/security/security-architecture/[Security Architecture of Jenkins]. +Specifically: -* jenkinsdoc:Permission[], which represents an activity that requires a security privilege. - This is usually a verb, like "configure", "administer", "tag", etc. -* `Authentication`, which represents the current user and roles (AKA groups) he/she has. - When a thread runs in Jenkins, it always carry an `Authentication` object implicitly, which represents the user that the thread is serving. (If a thread is a part of Jenkins and not serving any user request, like `Executor{`}s, then it carries an almighty "system" `Authentication` object.) -* jenkinsdoc:ACL[], which decides whether the `Authentication` object carried by the current thread has the given permission or not. -* jenkinsdoc:AccessControlled[], which is implemented by an object who owns ACL. - -So the overall picture is this; various objects in Jenkins (such as jenkinsdoc:Job[], jenkinsdoc:Jenkins[], jenkinsdoc:User[], jenkinsdoc:View[], etc.) are jenkinsdoc:AccessControlled[] objects, and therefore they own ACLs. -The code is then written in such a way that before a security-sensitive operation is performed, it checks ACL. - -For example, the following code is taken from the jenkinsdoc:Jenkins[] class, which lets you shut down the JVM by requesting `/exit`. -You can easily imagine that in a security sensitive environment you don't want random users to invoke this, so it makes sure that the caller has the "ADMINISTER" permission of the system before proceeding to do the work: - ----- - public void doExit( StaplerRequest req, StaplerResponse rsp ) throws IOException { - checkPermission(ADMINISTER); // <1> - LOGGER.severe(String.format("Shutting down VM as requested by %s from %s", - getAuthentication().getName(), req!=null?req.getRemoteAddr():"???")); - if (rsp!=null) { - rsp.setStatus(HttpServletResponse.SC_OK); - rsp.setContentType("text/plain"); - try (PrintWriter w = rsp.getWriter()) { - w.println("Shutting down"); - } - } +* Ensure that your code checks the ACL before performing a security-sensitive operation. +* Use the `StaplerProxy` interface to control read access to `AccessControlled` objects. - System.exit(0); - } ----- -<1> This throws an exception if the user accessing this URL doesn't have `Administer` permission. +Store user credentials as secrets:: -If the administrator configured no security mechanism, the checkPermission method simply becomes no-op. -The administrator could configure matrix-based ACL, in which case every `AccessControlled` object will share the single ACL (whose contents is controlled by the configuration done by the administrator.) In more elaborate case, each `AccessControlled` object might have different ACLs. -In all cases, this is the code you need to write. +Protect user credentials by storing them on disk in a field of type `Secret` +and never in a simple `String` field. +Protect user credentials by storing them on disk in a field of type `Secret` +and never in a simple `String` field. +Use a getter that returns the same type to access the `Secrets` field +from other code. +See +link:https://www.jenkins.io/doc/developer/security/secrets/[Storing Secrets] +for background information, instructions, and code examples. -== Controlling read access to `AccessControlled` objects +Implement appropriate script security:: -The recommended way to control read access to `AccessControlled` objects is to implement the `StaplerProxy` interface. -See link:read-access[Restricting HTTP Access to `AccessControlled` Objects] for more information. +Be sure that your plugin implements appropriate security +for custom Groovy scripts that users may need to create to customize Jenkins. -== What do plugins need to do to protect web methods? +For more information, see the _Developer's Guide_ section of the +link:https://plugins.jenkins.io/script-security/[Script Security] documentation. -* Identify the operations in code that can be potentially security sensitive. - This includes anything that can change state in the server, have other side effects (like elaborate form validation `doCheck` methods), or potentially discloses protected information (like auto-completion `doAutoComplete` methods). - These methods should perform `checkPermission`. -* Identify the nearest `AccessControlled` objects to check permissions with. - If your 'this' object is already access-controlled, then that's obviously it. - Otherwise, try to look for the nearest logical ancestor. - If all else fails, use the `Jenkins` singleton. -* Identify the `Permission` object to use. - If you extend from an `ExtensionPoint`, it might already define some permission objects as public static final fields in them. - If you are defining a sub-system of a substantial size, you might want to create new `Permission` objects (see the end of the `View` class for this example.) If you don't know, you can use `Jenkins.ADMINISTER` as a starting point. +Provide Role Check for Callable:: -With these three information, you can now insert: +Communication between the Jenkins controller and agents is implemented with the Java +link:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Callable.html[Callable] interface. +Plugins should always implement a _role check_ that runs after a +`Callable` message to ensure that the object executes on the proper side of the controller-agent communication. +Jenkins 2.319 and Jenkins LTS 2.303.3 and later releases enforce this behavior. +A plugin that does not comply throws a `SecurityException` and logs an error message. ----- -AccessControlled ac = ... do the step 2 above ... -Permission p = ... do the step 3 above ... -ac.checkPermission(p) ----- +See +link:/doc/developer/security/remoting-callables/[Remoting Callables] and +link:/doc/book/security/controller-isolation/required-role-check/[Required Role Check] +for more information. -See also link:form-validation[Securely implementing form validation]. -=== Checking permissions in Jelly files - -If your entire HTML page rendered by Jelly needs to be protected, you can use the attributes of the `` tag, like this: - ----- - ----- -The permission is always checked against the "it" object, so that needs to be an `AccessControlled` object. - -NOTE: This only prevents access to the view (e.g. configuration form), and does not prevent submissions to the form submission endpoints. -This will still need to be done as described in the previous section. - -==== Disabling a part of page rendering if the user doesn't have a permission - -Sometimes you'd like to change the page rendering, based on the user's permissions. -For example, if the user cannot delete a project, it doesn't make sense to show a link to do that. -To do this, write Jelly like this: ----- - - ... - ----- - -NOTE: This is not to be confused with the `checkPermission` invocation in your operation. -Users can still hit the URL directly, so you still need to protect the operation itself, in addition to disabling the UI rendering - -=== Authentication ways - -In Jenkins the security engine that is used is Spring Security. -Without any special plugins to manage authentication, an instance of Jenkins is packaged -with the following authentication ways: - -* Web UI -** When you use the form on the login page, using the fields `j_username` and `j_password` -* REST API -** Using Basic with login / *password* -** Using Basic with login / *apiToken* -* Jenkins CLI jar -** (deprecated) using remoting transport with login / logout command -** (deprecated) username / password as parameters on each command -** `-auth` argument with username:password or username:apiToken that will do something like HTTP calls -** using SSH transport mode with your local keys -* CLI over SSH -** directly using the native SSH command, without Jenkins CLI - -=== Authentication flow - -Depending on the authentication method you use, the processing flow will differ drastically. -By flow we mean the involved classes that will check your credentials for validity. - -==== Web UI and REST API - -image:web_rest_flow.svg["Web UI and REST API flow", role=center] - -In the diagram above, each arrow indicates a way to authenticate. - -Both the Web UI and the REST API using login / password will flow in the same `AbstractPasswordBasedSecurityRealm` -that delegates the real check to the configured `SecurityRealm`. -The credentials are retrieved for the first method by retrieving information in the POST and for the second by using the Basic Authentication (in header). -A point that is important to mention here, the Web UI is the only way (not deprecated) that use the Session to save the credentials. - -For the login / apiToken calls, the `BasicHeaderApiTokenAuthenticator` manages to check if the apiToken corresponds to the user with the given login. - -==== CLI (SSH and native) - -For the CLI part, the things become a bit more complicated, not by the complexity but more by the multiplicity of way to connect. - -image:cli_flow.svg["CLI flow", role=center] - -The first case (remoting) is deprecated but explained as potentially it's still used. -The principle is to create a sort of session between the login command and the logout one. -The authentication is checked using the same classes that we use for the Web UI or the REST API with password. -Once the authentication is verified, the credentials are stored in a local cache that will enable future calls to be authenticated automatically. - -The second way put the username and the password as additional parameters of the command (`--username` and `--password`). - -For the third and fourth ways, we pass the parameters to connect like in an HTTP call in the header. -The authentication is checked exactly the same way as for the REST API depending on the provided password or token. - -Last possibility for the Jenkins CLI is using the SSH transport mode offered by SSHD module (also available for plugins). -It uses normal SSH configuration using your local keys to authenticate. -It shares the same verifier with the Native CLI way. - -==== Other ways -The plugin have the possibility to propose a new `SecurityRealm` or implements some ``ExtensionPoint``s -(like https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/security/QueueItemAuthenticator.java[QueueItemAuthenticator]) -in order to provide new ways for a user to authenticate. - -=== Support for Locked/Disabled/Expired Accounts - -Some authentication providers support additional account validity attributes such as whether or not the account is locked, disabled, or expired. -Normally, these sorts of account validity checks are performed by the underlying authentication provider itself when authenticating a user with their password. -However, _until a user attempts to log in with their password, Jenkins is never notified of account status changes!_ -This means that without explicit support from its corresponding Jenkins authentication provider plugin, Jenkins will otherwise continue to allow the account to authenticate through the above-mentioned authentication methods (SSH keys, API tokens) until the account is also deleted or disabled in Jenkins by an administrator. -Authentication providers that can implement account validity checks through means other than attempting to log the user in should throw a subtype of `org.springframework.security.authentication.AccountStatusException` in `SecurityRealm.loadUserByUsername2`. //// https://wiki.jenkins.io/display/JENKINS/Making+your+plugin+behave+in+secured+Jenkins diff --git a/content/doc/developer/security/security-architecture.adoc b/content/doc/developer/security/security-architecture.adoc new file mode 100644 index 000000000000..33660602a6b5 --- /dev/null +++ b/content/doc/developer/security/security-architecture.adoc @@ -0,0 +1,182 @@ +--- +title: Security Architecture +layout: developerchapter +wip: true +references: +- url: https://plugins.jenkins.io/script-security#ScriptSecurityPlugin-Developer%E2%80%99sguide + title: Script Security Developer's Guide +--- + +:imagesdir: /doc/developer/security/resources + +// this is a straight import of https://wiki.jenkins.io/display/JENKINS/Making+your+plugin+behave+in+secured+Jenkins +// TODO check contents and remove wiki page + + +== Security Architecture of Jenkins + +Jenkins has a security mechanism in place so that the administrator of Jenkins can control who gets access to what part of Jenkins. +The key components of this mechanism are the followings: + +* jenkinsdoc:Permission[], which represents an activity that requires a security privilege. + This is usually a verb, like "configure", "administer", "tag", etc. +* `Authentication`, which represents the current user and roles (AKA groups) he/she has. + When a thread runs in Jenkins, it always carry an `Authentication` object implicitly, which represents the user that the thread is serving. (If a thread is a part of Jenkins and not serving any user request, like `Executor{`}s, then it carries an almighty "system" `Authentication` object.) +* jenkinsdoc:ACL[], which decides whether the `Authentication` object carried by the current thread has the given permission or not. +* jenkinsdoc:AccessControlled[], which is implemented by an object who owns ACL. + +So the overall picture is this; various objects in Jenkins (such as jenkinsdoc:Job[], jenkinsdoc:Jenkins[], jenkinsdoc:User[], jenkinsdoc:View[], etc.) are jenkinsdoc:AccessControlled[] objects, and therefore they own ACLs. +The code is then written in such a way that before a security-sensitive operation is performed, it checks ACL. + +For example, the following code is taken from the jenkinsdoc:Jenkins[] class, which lets you shut down the JVM by requesting `/exit`. +You can easily imagine that in a security sensitive environment you don't want random users to invoke this, so it makes sure that the caller has the "ADMINISTER" permission of the system before proceeding to do the work: + +---- + public void doExit( StaplerRequest req, StaplerResponse rsp ) throws IOException { + checkPermission(ADMINISTER); // <1> + LOGGER.severe(String.format("Shutting down VM as requested by %s from %s", + getAuthentication().getName(), req!=null?req.getRemoteAddr():"???")); + if (rsp!=null) { + rsp.setStatus(HttpServletResponse.SC_OK); + rsp.setContentType("text/plain"); + try (PrintWriter w = rsp.getWriter()) { + w.println("Shutting down"); + } + } + + System.exit(0); + } +---- +<1> This throws an exception if the user accessing this URL doesn't have `Administer` permission. + +If the administrator configured no security mechanism, the checkPermission method simply becomes no-op. +The administrator could configure matrix-based ACL, in which case every `AccessControlled` object will share the single ACL (whose contents is controlled by the configuration done by the administrator.) In more elaborate case, each `AccessControlled` object might have different ACLs. +In all cases, this is the code you need to write. + +== Controlling read access to `AccessControlled` objects + +The recommended way to control read access to `AccessControlled` objects is to implement the `StaplerProxy` interface. +See link:read-access[Restricting HTTP Access to `AccessControlled` Objects] for more information. + +== What do plugins need to do to protect web methods? + +* Identify the operations in code that can be potentially security sensitive. + This includes anything that can change state in the server, have other side effects (like elaborate form validation `doCheck` methods), or potentially discloses protected information (like auto-completion `doAutoComplete` methods). + These methods should perform `checkPermission`. +* Identify the nearest `AccessControlled` objects to check permissions with. + If your 'this' object is already access-controlled, then that's obviously it. + Otherwise, try to look for the nearest logical ancestor. + If all else fails, use the `Jenkins` singleton. +* Identify the `Permission` object to use. + If you extend from an `ExtensionPoint`, it might already define some permission objects as public static final fields in them. + If you are defining a sub-system of a substantial size, you might want to create new `Permission` objects (see the end of the `View` class for this example.) If you don't know, you can use `Jenkins.ADMINISTER` as a starting point. + +With these three information, you can now insert: + +---- +AccessControlled ac = ... do the step 2 above ... +Permission p = ... do the step 3 above ... +ac.checkPermission(p) +---- + +See also link:form-validation[Securely implementing form validation]. + +=== Checking permissions in Jelly files + +If your entire HTML page rendered by Jelly needs to be protected, you can use the attributes of the `` tag, like this: + +---- + +---- +The permission is always checked against the "it" object, so that needs to be an `AccessControlled` object. + +NOTE: This only prevents access to the view (e.g. configuration form), and does not prevent submissions to the form submission endpoints. +This will still need to be done as described in the previous section. + +==== Disabling a part of page rendering if the user doesn't have a permission + +Sometimes you'd like to change the page rendering, based on the user's permissions. +For example, if the user cannot delete a project, it doesn't make sense to show a link to do that. +To do this, write Jelly like this: +---- + + ... + +---- + +NOTE: This is not to be confused with the `checkPermission` invocation in your operation. +Users can still hit the URL directly, so you still need to protect the operation itself, in addition to disabling the UI rendering + +=== Authentication ways + +In Jenkins the security engine that is used is Spring Security. +Without any special plugins to manage authentication, an instance of Jenkins is packaged +with the following authentication ways: + +* Web UI +** When you use the form on the login page, using the fields `j_username` and `j_password` +* REST API +** Using Basic with login / *password* +** Using Basic with login / *apiToken* +* Jenkins CLI jar +** (deprecated) using remoting transport with login / logout command +** (deprecated) username / password as parameters on each command +** `-auth` argument with username:password or username:apiToken that will do something like HTTP calls +** using SSH transport mode with your local keys +* CLI over SSH +** directly using the native SSH command, without Jenkins CLI + +=== Authentication flow + +Depending on the authentication method you use, the processing flow will differ drastically. +By flow we mean the involved classes that will check your credentials for validity. + +==== Web UI and REST API + +image:web_rest_flow.svg["Web UI and REST API flow", role=center] + +In the diagram above, each arrow indicates a way to authenticate. + +Both the Web UI and the REST API using login / password will flow in the same `AbstractPasswordBasedSecurityRealm` +that delegates the real check to the configured `SecurityRealm`. +The credentials are retrieved for the first method by retrieving information in the POST and for the second by using the Basic Authentication (in header). +A point that is important to mention here, the Web UI is the only way (not deprecated) that use the Session to save the credentials. + +For the login / apiToken calls, the `BasicHeaderApiTokenAuthenticator` manages to check if the apiToken corresponds to the user with the given login. + +==== CLI (SSH and native) + +For the CLI part, the things become a bit more complicated, not by the complexity but more by the multiplicity of way to connect. + +image:cli_flow.svg["CLI flow", role=center] + +The first case (remoting) is deprecated but explained as potentially it's still used. +The principle is to create a sort of session between the login command and the logout one. +The authentication is checked using the same classes that we use for the Web UI or the REST API with password. +Once the authentication is verified, the credentials are stored in a local cache that will enable future calls to be authenticated automatically. + +The second way put the username and the password as additional parameters of the command (`--username` and `--password`). + +For the third and fourth ways, we pass the parameters to connect like in an HTTP call in the header. +The authentication is checked exactly the same way as for the REST API depending on the provided password or token. + +Last possibility for the Jenkins CLI is using the SSH transport mode offered by SSHD module (also available for plugins). +It uses normal SSH configuration using your local keys to authenticate. +It shares the same verifier with the Native CLI way. + +==== Other ways +The plugin have the possibility to propose a new `SecurityRealm` or implements some ``ExtensionPoint``s +(like https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/security/QueueItemAuthenticator.java[QueueItemAuthenticator]) +in order to provide new ways for a user to authenticate. + +=== Support for Locked/Disabled/Expired Accounts + +Some authentication providers support additional account validity attributes such as whether or not the account is locked, disabled, or expired. +Normally, these sorts of account validity checks are performed by the underlying authentication provider itself when authenticating a user with their password. +However, _until a user attempts to log in with their password, Jenkins is never notified of account status changes!_ +This means that without explicit support from its corresponding Jenkins authentication provider plugin, Jenkins will otherwise continue to allow the account to authenticate through the above-mentioned authentication methods (SSH keys, API tokens) until the account is also deleted or disabled in Jenkins by an administrator. +Authentication providers that can implement account validity checks through means other than attempting to log the user in should throw a subtype of `org.springframework.security.authentication.AccountStatusException` in `SecurityRealm.loadUserByUsername2`. + +//// +https://wiki.jenkins.io/display/JENKINS/Making+your+plugin+behave+in+secured+Jenkins +//// From 34c0f8155460bafd260b6627d1a129680194e845 Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Wed, 10 Nov 2021 19:49:48 -0800 Subject: [PATCH 06/15] add link to developer/security/index.adoc from book/security/index.adoc --- content/doc/book/security/index.adoc | 3 +++ content/doc/developer/security/index.adoc | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/content/doc/book/security/index.adoc b/content/doc/book/security/index.adoc index e131351f350b..7abb728e8b3d 100644 --- a/content/doc/book/security/index.adoc +++ b/content/doc/book/security/index.adoc @@ -61,3 +61,6 @@ link:user-content[Rendering User Content]:: By default, Jenkins strictly limits the features useable in user content (files from workspaces, archived artifacts, etc.) it serves. This chapter discusses how to customize this and make HTML reports and similar content both functional and safe to view. + _This is set up securely by default._ + +Information about security practices that are required from plugin developers and maintainters is in +link:http://localhost:4242/doc/developer/security/[Security for Plugin Developers]. diff --git a/content/doc/developer/security/index.adoc b/content/doc/developer/security/index.adoc index 41ab0861232f..e6f0d197f73c 100644 --- a/content/doc/developer/security/index.adoc +++ b/content/doc/developer/security/index.adoc @@ -1,5 +1,5 @@ --- -title: Security +title: Security for Plugin Developers layout: developerchapter wip: true references: From ca2d8fa46303feac305db40b57c0eb07ef965be8 Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Thu, 11 Nov 2021 00:40:34 -0800 Subject: [PATCH 07/15] Fix link URL --- content/doc/book/security/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/doc/book/security/index.adoc b/content/doc/book/security/index.adoc index 7abb728e8b3d..ae93188145d6 100644 --- a/content/doc/book/security/index.adoc +++ b/content/doc/book/security/index.adoc @@ -63,4 +63,4 @@ This chapter discusses how to customize this and make HTML reports and similar c _This is set up securely by default._ Information about security practices that are required from plugin developers and maintainters is in -link:http://localhost:4242/doc/developer/security/[Security for Plugin Developers]. +link:/doc/developer/security/[Security for Plugin Developers]. From 4a177a1944571dd3cdf3d8d74d65c2bce0f65a6d Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Thu, 11 Nov 2021 00:42:02 -0800 Subject: [PATCH 08/15] Fix link URL --- content/doc/developer/security/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/doc/developer/security/index.adoc b/content/doc/developer/security/index.adoc index e6f0d197f73c..0f61d5f3252e 100644 --- a/content/doc/developer/security/index.adoc +++ b/content/doc/developer/security/index.adoc @@ -20,7 +20,7 @@ It may be necessary to modify your plugin to work and comply with security fixes Conform to access permissions:: Understand and conform to the -link:http://localhost:4242/doc/developer/security/security-architecture/[Security Architecture of Jenkins]. +link:/doc/developer/security/security-architecture/[Security Architecture of Jenkins]. Specifically: * Ensure that your code checks the ACL before performing a security-sensitive operation. From d36895fd81b7359423dc4a05fcf337effa6b828b Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Thu, 11 Nov 2021 00:43:04 -0800 Subject: [PATCH 09/15] fix link url --- content/doc/developer/security/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/doc/developer/security/index.adoc b/content/doc/developer/security/index.adoc index 0f61d5f3252e..5a2952e5a937 100644 --- a/content/doc/developer/security/index.adoc +++ b/content/doc/developer/security/index.adoc @@ -35,7 +35,7 @@ and never in a simple `String` field. Use a getter that returns the same type to access the `Secrets` field from other code. See -link:https://www.jenkins.io/doc/developer/security/secrets/[Storing Secrets] +link:/doc/developer/security/secrets/[Storing Secrets] for background information, instructions, and code examples. Implement appropriate script security:: From 6e35dc75f8651fe708adcdec71c7ba5aa71b6e6f Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Thu, 11 Nov 2021 04:18:03 -0800 Subject: [PATCH 10/15] edit security-architecture --- .../security/security-architecture.adoc | 72 ++++++++++--------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/content/doc/developer/security/security-architecture.adoc b/content/doc/developer/security/security-architecture.adoc index 33660602a6b5..adf6cb27181b 100644 --- a/content/doc/developer/security/security-architecture.adoc +++ b/content/doc/developer/security/security-architecture.adoc @@ -1,5 +1,5 @@ --- -title: Security Architecture +title: Jenkins Security Architecture layout: developerchapter wip: true references: @@ -12,24 +12,25 @@ references: // this is a straight import of https://wiki.jenkins.io/display/JENKINS/Making+your+plugin+behave+in+secured+Jenkins // TODO check contents and remove wiki page - -== Security Architecture of Jenkins - -Jenkins has a security mechanism in place so that the administrator of Jenkins can control who gets access to what part of Jenkins. +Jenkins has a security mechanism that enables the Jenkins administrator to control who gets access to what part of Jenkins. The key components of this mechanism are the followings: * jenkinsdoc:Permission[], which represents an activity that requires a security privilege. This is usually a verb, like "configure", "administer", "tag", etc. -* `Authentication`, which represents the current user and roles (AKA groups) he/she has. - When a thread runs in Jenkins, it always carry an `Authentication` object implicitly, which represents the user that the thread is serving. (If a thread is a part of Jenkins and not serving any user request, like `Executor{`}s, then it carries an almighty "system" `Authentication` object.) +* `Authentication`, which represents the roles and groups for the current user. +When a thread runs in Jenkins, it implicitly carries an `Authentication` object, which represents the user being served by the thread. +// The next line had `Executor{`}s that did not render correctly +(If a thread is a part of Jenkins and not serving any user request, such as `Executor`, then it carries an almighty "system" `Authentication` object.) * jenkinsdoc:ACL[], which decides whether the `Authentication` object carried by the current thread has the given permission or not. * jenkinsdoc:AccessControlled[], which is implemented by an object who owns ACL. -So the overall picture is this; various objects in Jenkins (such as jenkinsdoc:Job[], jenkinsdoc:Jenkins[], jenkinsdoc:User[], jenkinsdoc:View[], etc.) are jenkinsdoc:AccessControlled[] objects, and therefore they own ACLs. -The code is then written in such a way that before a security-sensitive operation is performed, it checks ACL. +So the overall picture is this: + +* Various objects in Jenkins (such as jenkinsdoc:Job[], jenkinsdoc:Jenkins[], jenkinsdoc:User[], jenkinsdoc:View[], etc.) are jenkinsdoc:AccessControlled[] objects, and therefore they own ACLs. +* Plugin code should be written to check the ACL before performing a security-sensitive operation. For example, the following code is taken from the jenkinsdoc:Jenkins[] class, which lets you shut down the JVM by requesting `/exit`. -You can easily imagine that in a security sensitive environment you don't want random users to invoke this, so it makes sure that the caller has the "ADMINISTER" permission of the system before proceeding to do the work: +Clearly, random users should not be able to invoke this in a security-sensitive environment, so it makes sure that the caller has the "ADMINISTER" permission of the system before proceeding to do the work: ---- public void doExit( StaplerRequest req, StaplerResponse rsp ) throws IOException { @@ -49,8 +50,9 @@ You can easily imagine that in a security sensitive environment you don't want r ---- <1> This throws an exception if the user accessing this URL doesn't have `Administer` permission. -If the administrator configured no security mechanism, the checkPermission method simply becomes no-op. -The administrator could configure matrix-based ACL, in which case every `AccessControlled` object will share the single ACL (whose contents is controlled by the configuration done by the administrator.) In more elaborate case, each `AccessControlled` object might have different ACLs. +If the administrator did not configure a security mechanism, the `checkPermission` method simply becomes no-op. +The administrator could configure matrix-based ACL, in which case every `AccessControlled` object shares the single ACL (whose contents is controlled by the configuration done by the administrator.) +In more elaborate cases, each `AccessControlled` object could have different ACLs. In all cases, this is the code you need to write. == Controlling read access to `AccessControlled` objects @@ -58,20 +60,23 @@ In all cases, this is the code you need to write. The recommended way to control read access to `AccessControlled` objects is to implement the `StaplerProxy` interface. See link:read-access[Restricting HTTP Access to `AccessControlled` Objects] for more information. -== What do plugins need to do to protect web methods? +== Protecting Web Methods + +Plugins must do the following to protect web methods: * Identify the operations in code that can be potentially security sensitive. - This includes anything that can change state in the server, have other side effects (like elaborate form validation `doCheck` methods), or potentially discloses protected information (like auto-completion `doAutoComplete` methods). + This includes anything that can change state in the server, have other side effects (like elaborate form validation `doCheck` methods), or potentially disclose protected information (like auto-completion `doAutoComplete` methods). These methods should perform `checkPermission`. * Identify the nearest `AccessControlled` objects to check permissions with. - If your 'this' object is already access-controlled, then that's obviously it. + If your 'this' object is already access-controlled, use that. Otherwise, try to look for the nearest logical ancestor. If all else fails, use the `Jenkins` singleton. * Identify the `Permission` object to use. - If you extend from an `ExtensionPoint`, it might already define some permission objects as public static final fields in them. - If you are defining a sub-system of a substantial size, you might want to create new `Permission` objects (see the end of the `View` class for this example.) If you don't know, you can use `Jenkins.ADMINISTER` as a starting point. + If you extend from an `ExtensionPoint`, it might already define some permission objects as public static final fields. + If you are defining a sub-system of a substantial size, you may want to create new `Permission` objects (see the end of the `View` class for this example). +If you are unsure, use `Jenkins.ADMINISTER` as a starting point. -With these three information, you can now insert: +Based on this information, you can now insert: ---- AccessControlled ac = ... do the step 2 above ... @@ -83,7 +88,7 @@ See also link:form-validation[Securely implementing form validation]. === Checking permissions in Jelly files -If your entire HTML page rendered by Jelly needs to be protected, you can use the attributes of the `` tag, like this: +If your entire HTML page rendered by Jelly needs to be protected, use the attributes of the `` tag, like this: ---- @@ -93,10 +98,11 @@ The permission is always checked against the "it" object, so that needs to be an NOTE: This only prevents access to the view (e.g. configuration form), and does not prevent submissions to the form submission endpoints. This will still need to be done as described in the previous section. -==== Disabling a part of page rendering if the user doesn't have a permission +==== Modify page rendering based on permissions -Sometimes you'd like to change the page rendering, based on the user's permissions. -For example, if the user cannot delete a project, it doesn't make sense to show a link to do that. +==== Disabling a part of page rendering if the user doesn't have a permission +Page rendering can be modified based on the user's permissions. +For example, if the user cannot delete a project, it does not make sense to show a link to do that. To do this, write Jelly like this: ---- @@ -109,8 +115,9 @@ Users can still hit the URL directly, so you still need to protect the operation === Authentication ways -In Jenkins the security engine that is used is Spring Security. -Without any special plugins to manage authentication, an instance of Jenkins is packaged +Jenkins uses +link:https://spring.io/projects/spring-security[Spring Security] as its security engine. +With no special plugins that manage authentication installed, a Jenkins instance is packaged with the following authentication ways: * Web UI @@ -128,8 +135,8 @@ with the following authentication ways: === Authentication flow -Depending on the authentication method you use, the processing flow will differ drastically. -By flow we mean the involved classes that will check your credentials for validity. +the processing flow differs drastically depending on the authentication method you use. +By flow we mean the involved classes that check your credentials for validity. ==== Web UI and REST API @@ -150,22 +157,23 @@ For the CLI part, the things become a bit more complicated, not by the complexit image:cli_flow.svg["CLI flow", role=center] -The first case (remoting) is deprecated but explained as potentially it's still used. +Remoting is deprecated but explained because it may still be used. The principle is to create a sort of session between the login command and the logout one. The authentication is checked using the same classes that we use for the Web UI or the REST API with password. -Once the authentication is verified, the credentials are stored in a local cache that will enable future calls to be authenticated automatically. +After the authentication is verified, the credentials are stored in a local cache that enables future calls to be authenticated automatically. -The second way put the username and the password as additional parameters of the command (`--username` and `--password`). +The second way puts the username and the password as additional parameters of the command (`--username` and `--password`). For the third and fourth ways, we pass the parameters to connect like in an HTTP call in the header. The authentication is checked exactly the same way as for the REST API depending on the provided password or token. -Last possibility for the Jenkins CLI is using the SSH transport mode offered by SSHD module (also available for plugins). -It uses normal SSH configuration using your local keys to authenticate. +Last possibility for the Jenkins CLI is using the SSH transport mode offered by the SSHD module (also available for plugins). +It uses the normal SSH configuration using your local keys to authenticate. It shares the same verifier with the Native CLI way. ==== Other ways -The plugin have the possibility to propose a new `SecurityRealm` or implements some ``ExtensionPoint``s + +A plugin may propose a new `SecurityRealm` or implement some ``ExtensionPoint``s (like https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/security/QueueItemAuthenticator.java[QueueItemAuthenticator]) in order to provide new ways for a user to authenticate. From d7ecebf817e877bd5d409199500694815ab8370f Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Fri, 12 Nov 2021 15:41:49 -0800 Subject: [PATCH 11/15] edit form-validation; add to index.adoc checklist --- content/doc/developer/security/: | 77 +++++++++++++++++++ .../developer/security/form-validation.adoc | 43 ++++++----- content/doc/developer/security/index.adoc | 12 +++ 3 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 content/doc/developer/security/: diff --git a/content/doc/developer/security/: b/content/doc/developer/security/: new file mode 100644 index 000000000000..f781982094e2 --- /dev/null +++ b/content/doc/developer/security/: @@ -0,0 +1,77 @@ +--- +title: Security for Plugin Developers +layout: developerchapter +wip: true +references: +- url: https://plugins.jenkins.io/script-security#ScriptSecurityPlugin-Developer%E2%80%99sguide + title: Script Security Developer's Guide +--- + +Developers and maintainers of plugins play a crucial role in maintaining Jenkins security. +This chapter discusses the security practices required. + +Monitor security advisories:: + +Monitor Jenkins +link:https://www.jenkins.io/security/advisories/[Security Advisories] +closely. +It may be necessary to modify your plugin to work and comply with security fixes. + +Conform to access permissions:: + +Understand and conform to the +link:/doc/developer/security/security-architecture/[Security Architecture of Jenkins]. +Specifically: + +* Ensure that your code checks the ACL before performing a security-sensitive operation. +* Use the `StaplerProxy` interface to control read access to `AccessControlled` objects. + +Store user credentials as secrets:: + +Protect user credentials by storing them on disk in a field of type `Secret` +and never in a simple `String` field. +Protect user credentials by storing them on disk in a field of type `Secret` +and never in a simple `String` field. +Use a getter that returns the same type to access the `Secrets` field +from other code. +See +link:/doc/developer/security/secrets/[Storing Secrets] +for background information, instructions, and code examples. + +Implement appropriate script security:: + +Be sure that your plugin implements appropriate security +for custom Groovy scripts that users may need to create to customize Jenkins. + +For more information, see the _Developer's Guide_ section of the +link:https://plugins.jenkins.io/script-security/[Script Security] documentation. + +Provide Role Check for Callable:: + +Communication between the Jenkins controller and agents is implemented with the Java +link:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Callable.html[Callable] interface. +Plugins should always implement a _role check_ that runs after a +`Callable` message to ensure that the object executes on the proper side of the controller-agent communication. +Jenkins 2.319 and Jenkins LTS 2.303.3 and later releases enforce this behavior. +A plugin that does not comply throws a `SecurityException` and logs an error message. + +See +link:/doc/developer/security/remoting-callables/[Remoting Callables] and +link:/doc/book/security/controller-isolation/required-role-check/[Required Role Check] +for more information. + +Protect form validation methods from unauthorized accesss:: + +Form validation code can be used to compromise private information. +To protect against this: + +* Use a call to `Jenkins#checkPermission` to form validation code. + +* Only accept `POST` requests for form validation code with side effects for plugins that run on current Jenkins releases. +This protects your plugin from cross-site request forgery (CSRF) attacks. + +* Forms in plugins that run on older Jenkins releases may be sent using `GET` and need to use the `checkMethod` attribute. + +//// +https://wiki.jenkins.io/display/JENKINS/Making+your+plugin+behave+in+secured+Jenkins +//// diff --git a/content/doc/developer/security/form-validation.adoc b/content/doc/developer/security/form-validation.adoc index c87443b56ce8..ca8b1fabfbef 100644 --- a/content/doc/developer/security/form-validation.adoc +++ b/content/doc/developer/security/form-validation.adoc @@ -26,19 +26,19 @@ public FormValidation doCheckFoo(@QueryParameter String value) { } ---- -Stapler routing and Jenkins behavior will result in this method being routed at a URL like `/descriptorByName/f.q.ClassName/checkFoo`. -This URL will contain a minimal HTML snippet with a form validation message (if present) based on the presence and value of the `value` query parameter. +Stapler routing and Jenkins behavior result in this method being routed at a URL like `/descriptorByName/f.q.ClassName/checkFoo`. +This URL contains a minimal HTML snippet with a form validation message (if present) based on the presence and value of the `value` query parameter. -=== Potential Security Issues +== Potential Security Issues -==== Returning Private Information +=== Returning Private Information By default, any user with Overall/Read access can access form validation methods like the example method above. Some form validation methods could be used to infer private information, and as such may need to be protected from unauthorized access. If a form validation method is supposed to only be accessible to users with specific permissions, a permission check should be added. -==== Side Effects +=== Side Effects Form validation can become quite complex and have side effects. For example, Jenkins might evaluate a Groovy script passed as parameter, or access a URL passed as parameter. @@ -48,9 +48,9 @@ Ensuring that form validation code such as this is protected with appropriate pe link:https://en.wikipedia.org/wiki/Cross-site_request_forgery[Cross-site request forgery] is an attack on users with the necessary privileges and exploits the trust Jenkins has in these legitimate users' web browsers. Protecting from these attacks requires that form validation methods with side effects only accept `POST` requests. -=== Implementing Form Validation +== Implementing Form Validation -==== Checking permissions +=== Checking permissions To check for global permissions like `Administer`, add a call to `Jenkins#checkPermission`. Note that Overall/Read permission is always implied (unless you specifically implement jenkinsdoc:UnprotectedRootAction[]). @@ -82,18 +82,20 @@ public FormValidation doCheckFoo(@QueryParameter String value, @AncestorInPath I } ---- -==== Protecting from CSRF +=== Protecting from CSRF Stapler web methods, like form validation, can be invoked using any HTTP verb by default. This can be used by malicious users to attack an application by way of its legitimate users: -Cross-site request forgery is the result of a web application (Jenkins) trusting legitimate users' browser. +Cross-site request forgery is the result of a web application (Jenkins) trusting a legitimate user's browser. -To prevent this, Jenkins includes CSRF protection that requires actions with side effects (POST requests) to submit a user-specific secret, called a _crumb_. -To ensure this protection is relevant, web methods with side effects need to reject requests not sent via POST. +To prevent this, Jenkins includes CSRF protection that requires actions with side effects (`POST` requests) to submit a user-specific secret, called a _crumb_. +To ensure that this protection is relevant, web methods with side effects need to reject requests not sent via `POST`. There are two options to achieve this in general: -* staplerdoc:org.kohsuke.stapler.verb.POST[`POST`] limits processing to just the POST verb, and all other verbs will receive a 404 response. This is recommended approach for form validation methods. -* staplerdoc:org.kohsuke.stapler.interceptor.RequirePOST[`RequirePOST`] is the older (and more common) approach. It will show a form allowing users to resubmit the request using POST if they used a different verb. This is mostly useful for simple API actions. +* staplerdoc:org.kohsuke.stapler.verb.POST[`POST`] limits processing to just the POST verb, and all other verbs receive a 404 response. This is the recommended approach for form validation methods. +* staplerdoc:org.kohsuke.stapler.interceptor.RequirePOST[`RequirePOST`] is the older (and more common) approach. +It shows a form that allows users to resubmit the request using `POST` if they used a different verb. +This is mostly useful for simple API actions. Applying this protection is as simple as adding the annotation to the method: @@ -108,8 +110,8 @@ public FormValidation doCheckFoo(@QueryParameter String value) { } ---- -Depending on the versions of Jenkins supported by your plugin, these form validation methods may be invoked using HTTP GET, however, so the form may need to be adapted as well. -The Jenkins form Jelly controls support the `checkMethod` attribute, which, if set to `post`, will result in form validation being invoked via HTTP POST. +Depending on the versions of Jenkins supported by your plugin, however, these form validation methods may be invoked using `HTTP GET`, so the form may need to be adapted as well. +The Jenkins form Jelly controls support the `checkMethod` attribute, which, if set to `post`, results in form validation being invoked via `HTTP POST`: [source, xml] ---- @@ -118,11 +120,12 @@ The Jenkins form Jelly controls support the `checkMethod` attribute, which, if s ---- -The default behavior of form controls has changed over time, so you may not need to add the `checkMethod` attribute depending on the versions of Jenkins supported by your plugin and the types of form controls that have validation: +The default behavior of form controls has changed over time, so you may not need to add the `checkMethod` attribute, depending on the versions of Jenkins supported by your plugin and the types of form controls that have validation: -* Historically, form validation requests were sent using GET by default (with the exception of `f:validateButton`, which always used POST). +* Historically, form validation requests were sent using `GET` by default (with the exception of `f:validateButton`, which always used `POST`). * Since Jenkins 2.84 and 2.73.3, `f:password` always sends form validation as `POST`. -* Since Jenkins 2.285, most other form controls send form validation requests as `POST` by default, and `checkMethod` would only opt out. -* As of Jenkins 2.300 `f:checkbox` does not support the `checkMethod` attribute at all and requests are always sent using GET. +* Since Jenkins 2.285, most other form controls send form validation requests as `POST` by default, and `checkMethod` only opts out. +* As of Jenkins 2.300 `f:checkbox` does not support the `checkMethod` attribute at all and requests are always sent using `GET`. + +NOTE: Some basic form controls may not declare the `checkMethod` attribute in older versions of Jenkins. Depending on the control, it may still work, despite an error shown in your IDE. -NOTE: Some basic form controls may not declare the `checkMethod` attribute in older versions of Jenkins. Depending on the control it could still work, despite an error shown in your IDE. diff --git a/content/doc/developer/security/index.adoc b/content/doc/developer/security/index.adoc index 5a2952e5a937..456961094289 100644 --- a/content/doc/developer/security/index.adoc +++ b/content/doc/developer/security/index.adoc @@ -60,7 +60,19 @@ link:/doc/developer/security/remoting-callables/[Remoting Callables] and link:/doc/book/security/controller-isolation/required-role-check/[Required Role Check] for more information. +Protect form validation methods from unauthorized accesss:: +Form validation code can be used to compromise private information. +To protect against this: + +* Use a call to `Jenkins#checkPermission` to form validation code. + +* Only accept `POST` requests for form validation code with side effects for plugins that run on current Jenkins releases. +This protects your plugin from cross-site request forgery (CSRF) attacks. + +* Forms in plugins that run on older Jenkins releases may be sent using `GET` and need to use the `checkMethod` attribute. + +See link:http://localhost:4242/doc/developer/security/form-validation/#returning-private-information[Securely implementing form validation] for details. //// https://wiki.jenkins.io/display/JENKINS/Making+your+plugin+behave+in+secured+Jenkins From 318aeaf02c5eeaabb71720719579b8f9af577812 Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Thu, 9 May 2024 20:07:15 -0700 Subject: [PATCH 12/15] delete duplicate item about disk storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hervé Le Meur <91831478+lemeurherve@users.noreply.github.com> --- content/doc/developer/security/: | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/doc/developer/security/: b/content/doc/developer/security/: index f781982094e2..5c206274b57e 100644 --- a/content/doc/developer/security/: +++ b/content/doc/developer/security/: @@ -28,8 +28,6 @@ Specifically: Store user credentials as secrets:: -Protect user credentials by storing them on disk in a field of type `Secret` -and never in a simple `String` field. Protect user credentials by storing them on disk in a field of type `Secret` and never in a simple `String` field. Use a getter that returns the same type to access the `Secrets` field From 82cdd09cca8f010ed5a5935b4a2653887112921c Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Thu, 9 May 2024 20:07:38 -0700 Subject: [PATCH 13/15] capitalization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hervé Le Meur <91831478+lemeurherve@users.noreply.github.com> --- content/doc/developer/security/security-architecture.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/doc/developer/security/security-architecture.adoc b/content/doc/developer/security/security-architecture.adoc index adf6cb27181b..c06cecbac126 100644 --- a/content/doc/developer/security/security-architecture.adoc +++ b/content/doc/developer/security/security-architecture.adoc @@ -135,7 +135,7 @@ with the following authentication ways: === Authentication flow -the processing flow differs drastically depending on the authentication method you use. +The processing flow differs drastically depending on the authentication method you use. By flow we mean the involved classes that check your credentials for validity. ==== Web UI and REST API From 67a4e53fed92e1ae15ae1905c40a6fb1060092bb Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Thu, 9 May 2024 20:08:16 -0700 Subject: [PATCH 14/15] Duplicated text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hervé Le Meur <91831478+lemeurherve@users.noreply.github.com> --- content/doc/developer/security/index.adoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/doc/developer/security/index.adoc b/content/doc/developer/security/index.adoc index 456961094289..e4ffdbe36339 100644 --- a/content/doc/developer/security/index.adoc +++ b/content/doc/developer/security/index.adoc @@ -28,8 +28,6 @@ Specifically: Store user credentials as secrets:: -Protect user credentials by storing them on disk in a field of type `Secret` -and never in a simple `String` field. Protect user credentials by storing them on disk in a field of type `Secret` and never in a simple `String` field. Use a getter that returns the same type to access the `Secrets` field From 18756080c59981d1a5aab711dba340948c50015e Mon Sep 17 00:00:00 2001 From: Meg McRoberts Date: Thu, 9 May 2024 20:19:59 -0700 Subject: [PATCH 15/15] wordsmithing CLI section --- content/doc/developer/security/security-architecture.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/doc/developer/security/security-architecture.adoc b/content/doc/developer/security/security-architecture.adoc index c06cecbac126..299c6c1c6d99 100644 --- a/content/doc/developer/security/security-architecture.adoc +++ b/content/doc/developer/security/security-architecture.adoc @@ -153,19 +153,19 @@ For the login / apiToken calls, the `BasicHeaderApiTokenAuthenticator` manages t ==== CLI (SSH and native) -For the CLI part, the things become a bit more complicated, not by the complexity but more by the multiplicity of way to connect. +The security architecture of Jenkins CLI is a bit more complicated because of the multiplicity of ways to connect. image:cli_flow.svg["CLI flow", role=center] Remoting is deprecated but explained because it may still be used. The principle is to create a sort of session between the login command and the logout one. -The authentication is checked using the same classes that we use for the Web UI or the REST API with password. +The authentication is checked using the same classes that are used for the Web UI or the REST API with password. After the authentication is verified, the credentials are stored in a local cache that enables future calls to be authenticated automatically. The second way puts the username and the password as additional parameters of the command (`--username` and `--password`). For the third and fourth ways, we pass the parameters to connect like in an HTTP call in the header. -The authentication is checked exactly the same way as for the REST API depending on the provided password or token. +The authentication is checked exactly the same way as for the REST API, depending on the provided password or token. Last possibility for the Jenkins CLI is using the SSH transport mode offered by the SSHD module (also available for plugins). It uses the normal SSH configuration using your local keys to authenticate.