Мы решили это с помощью класса ниже. Просто вызовите метод аутентификации:
import java.text.MessageFormat;
import java.util.*;
import javax.naming.*;
import org.apache.log4j.Level;
public class LdapGroupAuthenticator {
public static final String DISTINGUISHED_NAME = "distinguishedName";
public static final String CN = "cn";
public static final String MEMBER = "member";
public static final String MEMBER_OF = "memberOf";
public static final String SEARCH_BY_SAM_ACCOUNT_NAME = "(SAMAccountName={0})";
public static final String SEARCH_GROUP_BY_GROUP_CN = "(&(objectCategory=group)(cn={0}))";
/*
* Prepares and returns CN that can be used for AD query
* e.g. Converts "CN=**Dev - Test Group" to "**Dev - Test Group"
* Converts CN=**Dev - Test Group,OU=Distribution Lists,DC=DOMAIN,DC=com to "**Dev - Test Group"
*/
public static String getCN(String cnName) {
if (cnName != null && cnName.toUpperCase().startsWith("CN=")) {
cnName = cnName.substring(3);
}
int position = cnName.indexOf(',');
if (position == -1) {
return cnName;
} else {
return cnName.substring(0, position);
}
}
public static boolean isSame(String target, String candidate) {
if (target != null && target.equalsIgnoreCase(candidate)) {
return true;
}
return false;
}
public static boolean authenticate(String domain, String username, String password) {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://1.2.3.4:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, domain + "\\" + username);
env.put(Context.SECURITY_CREDENTIALS, password);
DirContext ctx = null;
String defaultSearchBase = "DC=DOMAIN,DC=com";
String groupDistinguishedName = "DN=CN=DLS-APP-MyAdmin-C,OU=DLS File Permissions,DC=DOMAIN,DC=com";
try {
ctx = new InitialDirContext(env);
// userName is SAMAccountName
SearchResult sr = executeSearchSingleResult(ctx, SearchControls.SUBTREE_SCOPE, defaultSearchBase,
MessageFormat.format( SEARCH_BY_SAM_ACCOUNT_NAME, new Object[] {username}),
new String[] {DISTINGUISHED_NAME, CN, MEMBER_OF}
);
String groupCN = getCN(groupDistinguishedName);
HashMap processedUserGroups = new HashMap();
HashMap unProcessedUserGroups = new HashMap();
// Look for and process memberOf
Attribute memberOf = sr.getAttributes().get(MEMBER_OF);
if (memberOf != null) {
for ( Enumeration e1 = memberOf.getAll() ; e1.hasMoreElements() ; ) {
String unprocessedGroupDN = e1.nextElement().toString();
String unprocessedGroupCN = getCN(unprocessedGroupDN);
// Quick check for direct membership
if (isSame (groupCN, unprocessedGroupCN) && isSame (groupDistinguishedName, unprocessedGroupDN)) {
Log.info(username + " is authorized.");
return true;
} else {
unProcessedUserGroups.put(unprocessedGroupDN, unprocessedGroupCN);
}
}
if (userMemberOf(ctx, defaultSearchBase, processedUserGroups, unProcessedUserGroups, groupCN, groupDistinguishedName)) {
Log.info(username + " is authorized.");
return true;
}
}
Log.info(username + " is NOT authorized.");
return false;
} catch (AuthenticationException e) {
Log.info(username + " is NOT authenticated");
return false;
} catch (NamingException e) {
throw new SystemException(e);
} finally {
if (ctx != null) {
try {
ctx.close();
} catch (NamingException e) {
throw new SystemException(e);
}
}
}
}
public static boolean userMemberOf(DirContext ctx, String searchBase, HashMap processedUserGroups, HashMap unProcessedUserGroups, String groupCN, String groupDistinguishedName) throws NamingException {
HashMap newUnProcessedGroups = new HashMap();
for (Iterator entry = unProcessedUserGroups.keySet().iterator(); entry.hasNext();) {
String unprocessedGroupDistinguishedName = (String) entry.next();
String unprocessedGroupCN = (String)unProcessedUserGroups.get(unprocessedGroupDistinguishedName);
if ( processedUserGroups.get(unprocessedGroupDistinguishedName) != null) {
Log.info("Found : " + unprocessedGroupDistinguishedName +" in processedGroups. skipping further processing of it..." );
// We already traversed this.
continue;
}
if (isSame (groupCN, unprocessedGroupCN) && isSame (groupDistinguishedName, unprocessedGroupDistinguishedName)) {
Log.info("Found Match DistinguishedName : " + unprocessedGroupDistinguishedName +", CN : " + unprocessedGroupCN );
return true;
}
}
for (Iterator entry = unProcessedUserGroups.keySet().iterator(); entry.hasNext();) {
String unprocessedGroupDistinguishedName = (String) entry.next();
String unprocessedGroupCN = (String)unProcessedUserGroups.get(unprocessedGroupDistinguishedName);
processedUserGroups.put(unprocessedGroupDistinguishedName, unprocessedGroupCN);
// Fetch Groups in unprocessedGroupCN and put them in newUnProcessedGroups
NamingEnumeration ns = executeSearch(ctx, SearchControls.SUBTREE_SCOPE, searchBase,
MessageFormat.format( SEARCH_GROUP_BY_GROUP_CN, new Object[] {unprocessedGroupCN}),
new String[] {CN, DISTINGUISHED_NAME, MEMBER_OF});
// Loop through the search results
while (ns.hasMoreElements()) {
SearchResult sr = (SearchResult) ns.next();
// Make sure we're looking at correct distinguishedName, because we're querying by CN
String userDistinguishedName = sr.getAttributes().get(DISTINGUISHED_NAME).get().toString();
if (!isSame(unprocessedGroupDistinguishedName, userDistinguishedName)) {
Log.info("Processing CN : " + unprocessedGroupCN + ", DN : " + unprocessedGroupDistinguishedName +", Got DN : " + userDistinguishedName +", Ignoring...");
continue;
}
Log.info("Processing for memberOf CN : " + unprocessedGroupCN + ", DN : " + unprocessedGroupDistinguishedName);
// Look for and process memberOf
Attribute memberOf = sr.getAttributes().get(MEMBER_OF);
if (memberOf != null) {
for ( Enumeration e1 = memberOf.getAll() ; e1.hasMoreElements() ; ) {
String unprocessedChildGroupDN = e1.nextElement().toString();
String unprocessedChildGroupCN = getCN(unprocessedChildGroupDN);
Log.info("Adding to List of un-processed groups : " + unprocessedChildGroupDN +", CN : " + unprocessedChildGroupCN);
newUnProcessedGroups.put(unprocessedChildGroupDN, unprocessedChildGroupCN);
}
}
}
}
if (newUnProcessedGroups.size() == 0) {
Log.info("newUnProcessedGroups.size() is 0. returning false...");
return false;
}
// process unProcessedUserGroups
return userMemberOf(ctx, searchBase, processedUserGroups, newUnProcessedGroups, groupCN, groupDistinguishedName);
}
private static NamingEnumeration executeSearch(DirContext ctx, int searchScope, String searchBase, String searchFilter, String[] attributes) throws NamingException {
// Create the search controls
SearchControls searchCtls = new SearchControls();
// Specify the attributes to return
if (attributes != null) {
searchCtls.setReturningAttributes(attributes);
}
// Specify the search scope
searchCtls.setSearchScope(searchScope);
// Search for objects using the filter
NamingEnumeration result = ctx.search(searchBase, searchFilter,searchCtls);
return result;
}
private static SearchResult executeSearchSingleResult(DirContext ctx, int searchScope, String searchBase, String searchFilter, String[] attributes) throws NamingException {
NamingEnumeration result = executeSearch(ctx, searchScope, searchBase, searchFilter, attributes);
SearchResult sr = null;
// Loop through the search results
while (result.hasMoreElements()) {
sr = (SearchResult) result.next();
break;
}
return sr;
}
}
У меня довольно необычный: я делаю разработку Windows и Linux на той же машине . У меня есть виртуальная машина Linux, работающая под Linux. VirtualBox монтирует некоторые каталоги Windows и использует их непосредственно на машине Linux. Это позволяет мне использовать Windows для управления файлами, но для сборки в Linux. Это кросс-платформенный проект, поэтому он основывается как на Windows, так и на Linux из той же структуры каталогов.
Проблема в том, что системы сборки Linux и Windows врезаются друг в друга при использовании в одном каталоге; есть несколько сложных этапов сборки для загрузки библиотек и т. д., которые используют одни и те же имена каталогов. Windows-версия системы сборки загружает библиотеки, специфичные для Windows, и Linux-версия системы сборки загружает библиотеки, специфичные для Linux.
В идеальном мире система сборки будет изменена так, чтобы Windows & амп; Linux может сосуществовать внутри каталога, но на данный момент проблема решается с помощью рабочих деревьев. Папка «Linux» может генерировать артефакты сборки для Linux, а папка «Windows» может генерировать артефакты сборки Windows. Хотя это вряд ли идеальное решение, он делает приятную остановку, ожидая, когда будут исправлены ошибки системы сборки.
По общему признанию, worktree не был предназначен для этого; Я должен держать версию Windows и версию Linux в отдельных ветвях, хотя я бы предпочел, чтобы они были в одной ветке. Тем не менее, он выполняет свою работу, и это несколько нетрадиционный случай смены рабочего дня.
Одно очевидное использование - одновременное сравнение поведения (не источника) разных версий - например, различных версий веб-сайта или просто веб-страницы.
Я попытался это сделать локально.
page1
. src
и git init
it. src
создать page1.html
с $ git worktree add ../V0 ver0
src
мастер добавляет больше текста в page1.html
и фиксирует его. $ git branch sty1
page1.html
в ветке sty1
(добавьте некоторый отличительный стиль CSS) и добавьте commit it. $ git worktree add ../S1 sty1
Теперь вы можете использовать веб-браузер для одновременного открытия и просмотра этих трех версий:
..\page1\src\page1.html
// любой git имеет текущий ..\page1\V0\page1.html
// начальная версия ..\page1\S1\page1.html
// версия в экспериментальном стиле git log @{u}..
или git diff origin/feature/other-feature
может быть очень полезным, и это невозможно или более сложно. Эти идеи технически возможны с локальными клонами через ассортимент трудовых ресурсов, но каждое обходное решение, которое вы можете сделать, выполняется лучше и / или проще с помощью связанных рабочих деревьев. Вы можете делиться ссылками между рабочими. Если вы хотите сравнить или заимствовать изменения из другого локального филиала, теперь вы можете. git clone --reference
. Кроме того, управление всеми другими филиалами будет выполняться только один раз, а не один раз за рабочий каталог.
– Andreas Wederbrand
11 August 2015 в 10:53
В новом проекте для меня я создал функцию. Но некоторые спецификации не удались. Чтобы сравнить результаты с master
, я создал репозиторий work-tree
. Я сравнивал результаты шаг за шагом в коде запуска, пока не понял, что пошло не так.
tl; dr: В любой момент, когда вы хотите, чтобы два рабочих дерева проверялись одновременно, по какой-либо причине, git-worktree
- это быстрый и экономичный способ сделать это.
Если вы создайте другую рабочую строку, большинство разделов репо (т.е. .git
) будут разделены, то есть если вы создадите ветвь или извлечете данные, когда находитесь в одном дереве работ, она также будет доступна из любых других рабочих деревьев, которые у вас есть. Предположим, вы хотите запустить свой тестовый пакет на ветке foo, не нажимая его где-нибудь, чтобы клонировать его, и вы хотите избежать проблем с клонированием своего репо локально, используя git-worktree
, это отличный способ создать только новую проверку некоторых в отдельном месте, временно или постоянно. Точно так же, как с клоном, все, что вам нужно сделать, когда вы закончите с ним, - это удалить его, и ссылка на него будет собираться через некоторое время.
--force
. Но неудобно, если вы обновите ветку в одном месте и ожидаете работать над ней в другом, так как worktree не обновляется.
– jsageryd
27 February 2016 в 01:59
origin/master
.
– hypersw
29 February 2016 в 18:48
.git
в отдельной рабочей папке представляет собой текстовый файл, содержащий путь к его конфигурации, который находится в исходном репозитории.
– jsageryd
27 March 2016 в 10:41
git checkout --ignore-other-worktrees <branch>
git-scm.com/docs/git-checkout/…
– jsageryd
4 April 2017 в 13:38
Я изначально наткнулся на этот вопрос, подумав, что можно использовать для этих фантастических рабочих деревьев. С тех пор я включил их в свой рабочий процесс и, несмотря на свой первоначальный скептицизм, я пришел, чтобы найти их весьма полезными.
Я работаю над довольно большой базой кода, которая занимает довольно много времени для компиляции. Обычно у меня есть текущая ветвь развития на моей машине вместе с ветвью функций, в которой я сейчас работаю, плюс ведущая ветвь, представляющая текущее состояние живой системы.
Одно из самых больших преимуществ для меня очевидно, что мне не нужно перекомпилировать всю вещь каждый раз, когда я переключаю ветви (то есть рабочие). Хорошим побочным эффектом является то, что я могу пойти в рабочую среду разработки, сделать там что-то, сменить каталог на рабочую строку для моей текущей ветви функции, а затем переустановить ее без необходимости вытаскивать в первую очередь.
Для меня, git worktree - самое большое улучшение с давних времен. Я работаю над разработкой корпоративного программного обеспечения. Там очень часто приходится поддерживать старые версии, как то, что вы выпустили 3 года назад. Конечно, у вас есть ветка для каждой версии, чтобы вы могли легко переключиться на нее и исправить ошибку. Однако переключение дорого, потому что пока вы полностью реорганизовали хранилище и, возможно, создали систему. Если вы переключитесь, ваша среда IDE будет безумной, пытаясь адаптировать настройки проекта.
С помощью worktree вы можете избежать этой постоянной реконфигурации. Оформить эти ветви в отдельных папках с помощью рабочей таблицы. Для каждой ветви у вас есть независимый проект IDE.
Конечно, это могло быть сделано в прошлом путем клонирования репо несколько раз, и это был мой подход до сих пор. Тем не менее, это также означало расходование пространства жесткого диска и еще худшее, чтобы несколько раз получать одни и те же изменения от репо.
Теперь единственной недостающей частью является официальная версия git 2.5 для Windows, но есть надежда, что новый git для окон скоро выйдет: -)