Add 2.6 Audit log enhancements to Kubectl access path.

The enhancements added in https://github.com/rancher/rancher/issues/31166  need to also support the kubectl access path. When a user uses a kubeconfig file that passes through Rancher the username and IDP username need to be logged in the Rancher audit logs at level 1.  Additionally, they should be added into the kube-apiserver audit logs as well.

This fix is to support audit logging from kubectl access which use kubeconfig tokens. In case of kubeconfig, the AuthProvider is always set to "local", the userPrincipal is not found and is missing information. Hence the audit log data is not seen.
As a fix, the kubeconfig token is now fixed to carry the correct authProvider going forward.
Another part of the fix is instead reading extraInfo from user's login token, this is now read from userattributes where the extra info is saved after user logs in. This information can be found using the userId extracted from any token.
The userAttributes.Extra is also saved to ClusterUserAttributes.Extra field.
The process of finding the extra attributes for the user will be:
Check if extra attributes are found in userattributes for the token's provider
If the token's provider is empty or is local, then add all extraAttributes into the Audit entry to cover all IDP values
Fallback is read from token if found, or otherwise read from the user object

Here are some Audit Log samples

Rancher API audit Logs

Before fix, using kubeconfig tokens  having "local" set for admin user even if rancher has OpenLDAP enabled
Notice that the "extra" attributes are logged empty
{"auditID":"9823dcff-fb14-48a4-a99b-8d619d8aa1f7","requestURI":"/k8s/clusters/c-mfswt/api/v1/nodes?limit=500","user":{"name":"user-gpr69","group":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":[""],"username":[""]}},"method":"GET","remoteAddr":"<IP_ADDRESS>:42922","requestTimestamp":"2021-06-25T20:32:52Z","responseTimestamp":"2021-06-25T20:32:52Z","responseCode":200,"requestHeader":{"Accept":["application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json"],"Accept-Encoding":["gzip"],"Impersonate-Extra-Principalid":[""],"Impersonate-Extra-Username":[""],"Impersonate-Group":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"Impersonate-User":["user-gpr69"],"User-Agent":["kubectl/v1.18.8 (darwin/amd64) kubernetes/9f2892a"],"X-Forwarded-For":["<IP_ADDRESS>"],"X-Forwarded-Host":["ec2-3-137-201-13.us-east-2.compute.amazonaws.com"],"X-Forwarded-Port":["443"],"X-Forwarded-Proto":["https"],"X-Real-Ip":["<IP_ADDRESS>"],"X-Request-Id":["acfc8bbca8ecb36c8b741714e4abd9b3"],"X-Scheme":["https"]},"responseHeader":{"Audit-Id":["d46067fe-e491-4c91-bdef-50b7e6d98667"],"Cache-Control":["no-cache, private"],"Content-Type":["application/json"],"Date":["Fri, 25 Jun 2021 20:32:52 GMT"],"X-Api-Cattle-Auth":["true"],"X-Content-Type-Options":["nosniff"],"X-Kubernetes-Pf-Flowschema-Uid":["f9ebe668-ab6b-438e-b62c-dca5b9790e79"],"X-Kubernetes-Pf-Prioritylevel-Uid":["f97c7082-0b68-4c2a-9c15-4245073546c6"]}}
After this fix, using  the same old kubeconfig tokens  having "local" set
Notice that the "extra" attributes carry all IDP values associated to the user "testuser1"
{"auditID":"15e9c03d-5ea6-46f1-947d-377e7f2ac39c","requestURI":"/k8s/clusters/c-mfswt/api/v1/nodes?limit=500","user":{"name":"user-gpr69","group":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":["local://user-gpr69","openldap_user://uid=testuser1,ou=dev,dc=us-west-2,dc=compute,dc=internal"]}},"method":"GET","remoteAddr":"<IP_ADDRESS>:41148","requestTimestamp":"2021-06-25T21:01:39Z","responseTimestamp":"2021-06-25T21:01:39Z","responseCode":200,"requestHeader":{"Accept":["application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json"],"Accept-Encoding":["gzip"],"Impersonate-Extra-Principalid":["local://user-gpr69","openldap_user://uid=testuser1,ou=dev,dc=us-west-2,dc=compute,dc=internal"],"Impersonate-Group":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"Impersonate-User":["user-gpr69"],"User-Agent":["kubectl/v1.18.8 (darwin/amd64) kubernetes/9f2892a"],"X-Forwarded-For":["<IP_ADDRESS>"],"X-Forwarded-Host":["ec2-3-137-201-13.us-east-2.compute.amazonaws.com"],"X-Forwarded-Port":["443"],"X-Forwarded-Proto":["https"],"X-Real-Ip":["<IP_ADDRESS>"],"X-Request-Id":["60ca1d64ec12d5f9324a1a7f16dfe6cc"],"X-Scheme":["https"]},"responseHeader":{"Audit-Id":["40de9d12-d48f-40a6-8fd0-043cc22b17b5"],"Cache-Control":["no-cache, private"],"Content-Type":["application/json"],"Date":["Fri, 25 Jun 2021 21:01:39 GMT"],"X-Api-Cattle-Auth":["true"],"X-Content-Type-Options":["nosniff"],"X-Kubernetes-Pf-Flowschema-Uid":["f9ebe668-ab6b-438e-b62c-dca5b9790e79"],"X-Kubernetes-Pf-Prioritylevel-Uid":["f97c7082-0b68-4c2a-9c15-4245073546c6"]}}

K8s Audit Logs

Before fix, using kubeconfig tokens  having "local" set for admin user even if rancher has OpenLDAP enabled
Notice that the "extra" attributes are logged empty

{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"f9e73198-8403-48c5-b4a4-b5fe12530cbe","stage":"ResponseComplete","requestURI":"/api/v1/nodes?limit=500","verb":"list","user":{"username":"system:serviceaccount:cattle-system:kontainer-engine","uid":"4f63cb6f-c358-40ed-ab7a-6c79dc3b088f","groups":["system:serviceaccounts","system:serviceaccounts:cattle-system","system:authenticated"]},"impersonatedUser":{"username":"user-gpr69","groups":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":[""],"username":[""]}},"sourceIPs":["<IP_ADDRESS>","<IP_ADDRESS>","<IP_ADDRESS>"],"userAgent":"kubectl/v1.18.8 (darwin/amd64) kubernetes/9f2892a","objectRef":{"resource":"nodes","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2021-06-25T21:39:15.949258Z","stageTimestamp":"2021-06-25T21:39:15.956997Z","annotations":{"authentication.k8s.io/legacy-token":"system:serviceaccount:cattle-system:kontainer-engine","authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding "crb-eiwom4u62y" of ClusterRole "cluster-owner" to User "user-gpr69""}}

After fix, testuser1/admin using old kubeconfig token, the "extra" contains all principalIds

{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"40de9d12-d48f-40a6-8fd0-043cc22b17b5","stage":"ResponseComplete","requestURI":"/api/v1/nodes?limit=500","verb":"list","user":{"username":"system:serviceaccount:cattle-system:kontainer-engine","uid":"4f63cb6f-c358-40ed-ab7a-6c79dc3b088f","groups":["system:serviceaccounts","system:serviceaccounts:cattle-system","system:authenticated"]},"impersonatedUser":{"username":"user-gpr69","groups":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":["local://user-gpr69","openldap_user://uid=testuser1,ou=dev,dc=us-west-2,dc=compute,dc=internal"]}},"sourceIPs":["<IP_ADDRESS>","<IP_ADDRESS>","<IP_ADDRESS>"],"userAgent":"kubectl/v1.18.8 (darwin/amd64) kubernetes/9f2892a","objectRef":{"resource":"nodes","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2021-06-25T21:01:39.124672Z","stageTimestamp":"2021-06-25T21:01:39.135327Z","annotations":{"authentication.k8s.io/legacy-token":"system:serviceaccount:cattle-system:kontainer-engine","authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding "crb-eiwom4u62y" of ClusterRole "cluster-owner" to User "user-gpr69""}}

For a new user after the fix, k8s audit logs:

testuser3 after fix, new kubeconfig created with "openldap" provider set
{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"7dd6de32-d3ab-46a6-8571-99e3f2de15ac","stage":"ResponseComplete","requestURI":"/api/v1/nodes?limit=500","verb":"list","user":{"username":"system:serviceaccount:cattle-system:kontainer-engine","uid":"4f63cb6f-c358-40ed-ab7a-6c79dc3b088f","groups":["system:serviceaccounts","system:serviceaccounts:cattle-system","system:authenticated"]},"impersonatedUser":{"username":"u-e4pdqvmcdl","groups":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":["openldap_user://uid=testuser3,ou=dev,dc=us-west-2,dc=compute,dc=internal"],"username":["testuser3"]}},"sourceIPs":["<IP_ADDRESS>","<IP_ADDRESS>","<IP_ADDRESS>"],"userAgent":"kubectl/v1.18.8 (darwin/amd64) kubernetes/9f2892a","objectRef":{"resource":"nodes","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2021-06-25T21:12:52.166058Z","stageTimestamp":"2021-06-25T21:12:52.177702Z","annotations":{"authentication.k8s.io/legacy-token":"system:serviceaccount:cattle-system:kontainer-engine","authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding "crb-a6e5gxkpdw" of ClusterRole "cluster-member" to User "u-e4pdqvmcdl""}}
testuser3 from UI action after fix
{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"8762f868-fba5-42f8-ad77-5bf2703de13a","stage":"ResponseComplete","requestURI":"/apis/apps/v1/namespaces/ns3/deployments?timeout=45s","verb":"create","user":{"username":"system:serviceaccount:cattle-system:kontainer-engine","uid":"4f63cb6f-c358-40ed-ab7a-6c79dc3b088f","groups":["system:serviceaccounts","system:serviceaccounts:cattle-system","system:authenticated"]},"impersonatedUser":{"username":"u-e4pdqvmcdl","groups":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":["openldap_user://uid=testuser3,ou=dev,dc=us-west-2,dc=compute,dc=internal"],"username":["testuser3"]}},"sourceIPs":["<IP_ADDRESS>"],"userAgent":"rancher/v0.0.0 (linux/amd64) kubernetes/$Format cluster c-mfswt","objectRef":{"resource":"deployments","namespace":"ns3","name":"app3","apiGroup":"apps","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":201},"requestReceivedTimestamp":"2021-06-25T21:14:50.897540Z","stageTimestamp":"2021-06-25T21:14:50.921442Z","annotations":{"authentication.k8s.io/legacy-token":"system:serviceaccount:cattle-system:kontainer-engine","authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by RoleBinding "rb-ggjfhhho4c/ns3" of ClusterRole "admin" to User "u-e4pdqvmcdl""}}

From the above comment, it is observed that with the fixes using old KubeConfig tokens, still can leave the "username" field empty under "extra".
To cover this case, we now fallback on using the "displayName" field on user object.
With this, the audit logs with an old kubeconfig token look like this:

Github Auth, user "rancherdev"

Without fix, kubectl access

{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"5fda8072-cc82-4aaf-880e-064d1f8e93ff","stage":"ResponseComplete","requestURI":"/api/v1/nodes?limit=500","verb":"list","user":{"username":"system:serviceaccount:cattle-system:kontainer-engine","uid":"4f63cb6f-c358-40ed-ab7a-6c79dc3b088f","groups":["system:serviceaccounts","system:serviceaccounts:cattle-system","system:authenticated"]},"impersonatedUser":{"username":"u-4cnrgx47ty","groups":["github_org://9343010","github_team://1129756","github_team://1799375","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":[""],"username":[""]}},"sourceIPs":["<IP_ADDRESS>","<IP_ADDRESS>","<IP_ADDRESS>"],"userAgent":"kubectl/v1.18.8 (darwin/amd64) kubernetes/9f2892a","objectRef":{"resource":"nodes","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2021-06-29T17:39:32.156259Z","stageTimestamp":"2021-06-29T17:39:32.168005Z","annotations":{"authentication.k8s.io/legacy-token":"system:serviceaccount:cattle-system:kontainer-engine","authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding \"crb-jitulysuf7\" of ClusterRole \"cluster-member\" to User \"u-4cnrgx47ty\""}}

With fix:
{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"d96b747f-32db-4cc4-8cc2-8fcb8240e56b","stage":"ResponseComplete","requestURI":"/api/v1/nodes?limit=500","verb":"list","user":{"username":"system:serviceaccount:cattle-system:kontainer-engine","uid":"4f63cb6f-c358-40ed-ab7a-6c79dc3b088f","groups":["system:serviceaccounts","system:serviceaccounts:cattle-system","system:authenticated"]},"impersonatedUser":{"username":"u-4cnrgx47ty","groups":["github_org://9343010","github_team://1129756","github_team://1799375","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":["github_user://10679260","local://u-4cnrgx47ty"],"username":["Rancher Dev"]}},"sourceIPs":["<IP_ADDRESS>","<IP_ADDRESS>","<IP_ADDRESS>"],"userAgent":"kubectl/v1.18.8 (darwin/amd64) kubernetes/9f2892a","objectRef":{"resource":"nodes","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2021-06-29T17:46:01.984438Z","stageTimestamp":"2021-06-29T17:46:02.016907Z","annotations":{"authentication.k8s.io/legacy-token":"system:serviceaccount:cattle-system:kontainer-engine","authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding \"crb-jitulysuf7\" of ClusterRole \"cluster-member\" to User \"u-4cnrgx47ty\""}}

OpenLDAP Auth, user "testuser3"

Without fix, kubectl access
{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"70c5cf71-12f6-4093-84b8-5e5421125dde","stage":"ResponseComplete","requestURI":"/api/v1/nodes?limit=500","verb":"list","user":{"username":"system:serviceaccount:cattle-system:kontainer-engine","uid":"4f63cb6f-c358-40ed-ab7a-6c79dc3b088f","groups":["system:serviceaccounts","system:serviceaccounts:cattle-system","system:authenticated"]},"impersonatedUser":{"username":"u-e4pdqvmcdl","groups":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":[""],"username":[""]}},"sourceIPs":["<IP_ADDRESS>","<IP_ADDRESS>","<IP_ADDRESS>"],"userAgent":"kubectl/v1.18.8 (darwin/amd64) kubernetes/9f2892a","objectRef":{"resource":"nodes","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2021-06-28T17:47:21.614563Z","stageTimestamp":"2021-06-28T17:47:21.622568Z","annotations":{"authentication.k8s.io/legacy-token":"system:serviceaccount:cattle-system:kontainer-engine","authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding \"crb-a6e5gxkpdw\" of ClusterRole \"cluster-member\" to User \"u-e4pdqvmcdl\""}}

With fix:
{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"e4e69261-184b-46eb-9084-c55a4df3d392","stage":"ResponseComplete","requestURI":"/api/v1/nodes?limit=500","verb":"list","user":{"username":"system:serviceaccount:cattle-system:kontainer-engine","uid":"4f63cb6f-c358-40ed-ab7a-6c79dc3b088f","groups":["system:serviceaccounts","system:serviceaccounts:cattle-system","system:authenticated"]},"impersonatedUser":{"username":"u-e4pdqvmcdl","groups":["openldap_group://cn=caringQA,ou=groups,dc=us-west-2,dc=compute,dc=internal","openldap_group://cn=uniquegroup,ou=groupsDuplicate,dc=us-west-2,dc=compute,dc=internal","system:authenticated","system:cattle:authenticated"],"extra":{"principalid":["local://u-e4pdqvmcdl","openldap_user://uid=testuser3,ou=dev,dc=us-west-2,dc=compute,dc=internal"],"username":["testuser3"]}},"sourceIPs":["<IP_ADDRESS>","<IP_ADDRESS>","<IP_ADDRESS>"],"userAgent":"kubectl/v1.18.8 (darwin/amd64) kubernetes/9f2892a","objectRef":{"resource":"nodes","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2021-06-29T07:10:42.546997Z","stageTimestamp":"2021-06-29T07:10:42.570732Z","annotations":{"authentication.k8s.io/legacy-token":"system:serviceaccount:cattle-system:kontainer-engine","authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding \"crb-a6e5gxkpdw\" of ClusterRole \"cluster-member\" to User \"u-e4pdqvmcdl\""}}

Reproduction Environment
Rancher installed via
sudo docker run -d --restart=unless-stopped -p 80:80 -p 443:443 -v /var/log/rancher/auditlog:/var/log/auditlog -e AUDIT_LEVEL=1 --privileged rancher/rancher:v2.6.2

Component
Version / Type

Rancher version
2.6.2

Rancher cluster type
Single Node Docker Install

Docker version
20.10.7, build 20.10.7-0ubuntu5~20.04.2

Helm version
v2.16.8-rancher1

Downstream cluster type
N/A

Downstream K8s version
N/A

Browser type
Google Chrome

Browser version
95.0.4638.69 (Official Build) (x86_64)

Reproduction steps

Install Rancher with the following command

sudo docker run -d --restart=unless-stopped -p 80:80 -p 443:443 -v /var/log/rancher/auditlog:/var/log/auditlog -e AUDIT_LEVEL=1 --privileged rancher/rancher:v2.6.2

Starting from the default Rancher homepage /dashboard/home
Click hamburger menu -> click Users & Authentication -> click Auth Provider -> click OpenLDAP
Setup OpenLDAP as the authentication provider
After OpenLDAP is setup click hamburger menu ->  click local -> click Download KubeConfig
On your actual workstation locate the config file that was just downloaded and run the following

export KUBECONFIG=local.yaml

Run the following command

kubectl get pods -A

Now run these docker commands against the Rancher container

docker ps
docker cp INSERT-CONTAINER-ID-HERE:/var/log/auditlog/rancher-api-audi.log audit.log

If you want the audit.log on your workstation you can run this command

scp root@INSERT-RANCHER-IP-ADDRESS-HERE:audit.log /INSERT-PATH-WHERE-YOU-WANT-LOG-FILE-HERE/audit.log

Review the log file and see that principalid is missing

My checks PASSED

Validation Environment

Component
Version / Type

Rancher version
v2.6-cc2b8beb147322e7a7b8bebb81a8440d1e648c78-head

Rancher cluster type
Single Node Docker Install

Docker version
20.10.7, build 20.10.7-0ubuntu5~20.04.2

Helm version
v2.16.8-rancher1

Downstream cluster type
N/A

Downstream K8s version
N/A

Browser type
Google Chrome

Browser version
Version 95.0.4638.69 (Official Build) (x86_64)

Validation steps

Install Rancher via

 sudo docker run -d --restart=unless-stopped -p 80:80 -p 443:443 -v /var/log/rancher/auditlog:/var/log/auditlog -e AUDIT_LEVEL=1 --privileged rancher/rancher:v2.6-head

Starting from the default Rancher homepage /dashboard/home
Click hamburger menu -> click Users & Authentication -> click Auth Provider -> click OpenLDAP
Setup OpenLDAP as the authentication provider
After OpenLDAP is setup click hamburger menu ->  click local -> click Download KubeConfig
On your actual workstation locate the config file that was just downloaded and run the following

export KUBECONFIG=local.yaml

Run the following command

kubectl get pods -A

Now run these docker commands against the Rancher container

docker ps
docker cp INSERT-CONTAINER-ID-HERE:/var/log/auditlog/rancher-api-audit.log audit.log

If you want the audit.log on your workstation you can run this command

scp root@INSERT-RANCHER-IP-ADDRESS-HERE:audit.log /INSERT-PATH-WHERE-YOU-WANT-LOG-FILE-HERE/audit.log

Verified enhancements to Kubectl access path, and checked other tests in test plan.
Additional Info
Enhancement working


Update 1.15.2

Update mod to work with minecraft 1.15.2 and forge 31.1.0
Also cleaned the gradle build files and mods.toml in the process.
Does NOT increment mod version number

God, Didn't notice this. Rip my PR, this is much better.

@Insane96 Not so! Looking at your PR it seems I forgot two things which I have added to mine!

Thanks!


Add Spring Cloud Stream Binder for Event Grid

The Azure Event Grid(https://azure.microsoft.com/en-us/services/event-grid/) is available for a while now and it would be good if we had an implementation of Spring Cloud Stream Binder for Event Grid.

@emivaljr Thanks for your feedback, we'll consider this feature.

Any updates on this?

@vchernogorov No, this feature is still in our backlog.

Hi, do we have spring cloud functions supported on Event Grid events

@sankar228 sorry for the late response. Which spring cloud functions are you referring to?

Closing this issue.
Because it's not active for a long time.
If anyone have similar issue, please create issue in new repo: https://github.com/Azure/azure-sdk-for-java/issues


[Android] I'd like to use android:windowSoftInputMode="adjustResize" with webview.

Environment
Flutter version: Channel stable, 3.13.7
Plugin version: flutter_inappwebview: 6.0.0-beta.22
Description
I would like to know if it is possible to add the value android:windowSoftInputMode="adjustResize" to an Android WebView activity.
AndroidManifest.xml

...
<application>
    ...
    <activity>
        ...
        android:windowSoftInputMode="adjustResize">
    </activity>
    ...
</application>
...

If there is already a way to do this, please let me know how.
Thanks.

I'd like to apply adjustResize when the keyboard activated in the webview.
It work fine on iOS, but not on Android.
Is there a solution?


Timeout on response receiver and more logging

After some debugging with @luckysori we cannot understand why the receiver would sometimes not finish.
To make this more resilient we apply a timeout and add more logging to understand better what is happening.
Let's run this on testnet for a while to see how it behaves. This solution is not perfect, but it should be resilient enough to do the job.

bors r+


Need updatedBy or deletedBy recording feature?

Describe the feature
Can add updatedBy or deletedBy recording feature?
Motivation
If model have updatedBy or deletedBy property and  them not nil save it to database
Related Issues

Not going to support this in soft delete, maybe you can implement another plugin to do the job