-
Notifications
You must be signed in to change notification settings - Fork 8k
Implement forced password change for LDAP federated user (password policy control) #15253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
tsaarni
wants to merge
1
commit into
keycloak:main
Choose a base branch
from
Nordix:ldap-forced-password-change
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
federation/ldap/src/main/java/org/keycloak/storage/ldap/idm/store/ldap/BERDecoder.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| /* | ||
| * Copyright 2024 Red Hat, Inc. and/or its affiliates | ||
| * and other contributors as indicated by the @author tags. | ||
| * | ||
| * 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 | ||
| * | ||
| * http://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.keycloak.storage.ldap.idm.store.ldap; | ||
|
|
||
| import java.io.IOException; | ||
| import java.nio.BufferUnderflowException; | ||
| import java.nio.ByteBuffer; | ||
|
|
||
|
|
||
| /** | ||
| * A decoder for the ASN.1 BER encoding. | ||
| * | ||
| * Very limited implementation, only supports what is needed by the current LDAP extension controls. | ||
| */ | ||
| public class BERDecoder { | ||
| // Universal tags. | ||
| public static final int TAG_SEQUENCE = 0x30; | ||
|
|
||
| // Tag classes. | ||
| public static final int TAG_CLASS_CONTEXT_SPECIFIC = 0x80; | ||
|
|
||
| // Tag forms. | ||
| public static final int TAG_FORM_PRIMITIVE = 0x00; | ||
|
|
||
| private ByteBuffer encoded; | ||
|
|
||
| public BERDecoder(byte[] encodedValue) { | ||
| this.encoded = ByteBuffer.wrap(encodedValue); | ||
| } | ||
|
|
||
| /** | ||
| * Start decoding a sequence. | ||
| */ | ||
| public void startSequence() throws DecodeException { | ||
| try { | ||
| byte tag = encoded.get(); | ||
| if (tag != TAG_SEQUENCE) { | ||
| throw new DecodeException("Expected SEQUENCE (" + TAG_SEQUENCE + ") but got " + tag); | ||
| } | ||
| readLength(); | ||
| } catch (BufferUnderflowException e) { | ||
| throw new DecodeException("Unexpected end of input"); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Check if the next element matches with the given tag, but do not consume it. | ||
| */ | ||
| public boolean isNextTag(int clazz, int form, int tag) throws DecodeException { | ||
| encoded.mark(); | ||
| try { | ||
| int expected = clazz | form | tag; | ||
| int unsignedTag = encoded.get() & 0xFF; | ||
| encoded.reset(); | ||
| return unsignedTag == expected; | ||
| } catch (BufferUnderflowException e) { | ||
| throw new DecodeException("Unexpected end of input"); | ||
| } finally { | ||
| encoded.reset(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Skip over the next element. | ||
| */ | ||
| public void skipElement() throws DecodeException { | ||
| try { | ||
| int length = readLength(); | ||
| encoded.position(encoded.position() + length); | ||
| } catch (BufferUnderflowException e) { | ||
| throw new DecodeException("Unexpected end of input"); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Drain the value bytes of the next element. | ||
| */ | ||
| public byte[] drainElementValue() throws DecodeException { | ||
| try { | ||
| int length = readLength(); | ||
| byte[] value = new byte[length]; | ||
| encoded.get(value); | ||
| return value; | ||
| } catch (BufferUnderflowException e) { | ||
| throw new DecodeException("Unexpected end of input"); | ||
| } | ||
| } | ||
|
|
||
| private int readLength() throws DecodeException { | ||
| int length = encoded.get() & 0xFF; | ||
|
|
||
| // Short form. | ||
| if ((length & 0x80) == 0) { | ||
| return length; | ||
| } | ||
|
|
||
| // Long form. | ||
| int numBytes = length & 0x7F; | ||
| if (numBytes > 4) { | ||
| throw new DecodeException("Cannot handle more than 4 bytes of length, got " + numBytes + " bytes"); | ||
| } | ||
|
|
||
| length = 0; | ||
| for (int i = 0; i < numBytes; i++) { | ||
| length = (length << 8) | (encoded.get() & 0xFF); | ||
| } | ||
|
|
||
| return length; | ||
| } | ||
|
|
||
| public static final class DecodeException extends IOException { | ||
| DecodeException(String message) { | ||
| super(message); | ||
| } | ||
| } | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see calling
closeis basically setting the secret to null but I'm not sure if we want to remove calling it for the sake of respecting the expectations around vault secrets where we might want to clean-up resources for whatever reason.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm suggesting not having
vaultStringSecretas a member variable at all, therefore removal ofclose(). Though, in case ofvaultStringSecret.close()was overwritten as an empty method, so I think it had no effect.I'm suggesting removal of
vaultStringSecretmember sinceOptionalcomplicated finding the bind password unnecessarily in several places. I'm suggesting having new method that handles that in single place and has the vault secret as a local variable: