인터넷을 뒤지다 보니 Spring Security와 Active Directory를 연동하는 또 다른 방식이 있다.

이 방식은 Customize된 Authentication Class를 생성해야 하는 단점이 있다.

하지만 반대로 우리와 같이 LDAP 연동시 Authorization 관련 로직을 Customize 할 때 쉬울 듯 하다.( 뭐 아직은 해보지 않은 상태 지만 내부 코드를 보면 Role 명을 쉽게 입력할 수 있을 것 같다. )

그리고 인증 방식은 LDAP 형태가 아닌 Computer Name\사용자 계정 형태이다.
( 이 부분이 AD가 아닌 Window 내부 사용자 계정 관리 방식으로 보여 조금 꺼림직 하다. )

하지만 관리자 계정 정보를 필요로 하지 않는 다는 엄청난(?) 장점이 있다.

출처 : http://stackoverflow.com/questions/84680/how-do-you-authenticate-against-an-active-directory-server-using-spring-security 첫번째 댓글

[Spring Security Config]
<beans:bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
       
<beans:constructor-arg value="ldap://hostname.queso.com:389/" />
</beans:bean>

<beans:bean id="ldapAuthenticationProvider" class="org.queso.ad.service.authentication.LdapAuthenticationProvider">
       
<beans:property name="authenticator" ref="ldapAuthenticator" />
       
<custom-authentication-provider />
</beans:bean>

<beans:bean id="ldapAuthenticator" class="org.queso.ad.service.authentication.LdapAuthenticatorImpl">
       
<beans:property name="contextFactory" ref="contextSource" />
       
<beans:property name="principalPrefix" value="QUESO\" />
</beans:bean>

위 내용 중 principalPrefix는 Computuer 명 을 넣으면 된다.
즉 인증시 "컴퓨터명\사용자ID"가 LDAP 서버로 전달된다.

[LdapAuthenticationProvider.java]
/**
 * Custom Spring Security authentication provider which tries to bind to an LDAP server with
 * the passed-in credentials; of note, when used with the custom {@link LdapAuthenticatorImpl},
 * does <strong>not</strong> require an LDAP username and password for initial binding.
 *
 * @author Jason
 */
public class LdapAuthenticationProvider implements AuthenticationProvider {
private LdapAuthenticator authenticator;

       
public Authentication authenticate(Authentication auth) throws AuthenticationException {

               
// Authenticate, using the passed-in credentials.
               
DirContextOperations authAdapter = authenticator.authenticate(auth);

               
// Creating an LdapAuthenticationToken (rather than using the existing Authentication
               
// object) allows us to add the already-created LDAP context for our app to use later.
               
LdapAuthenticationToken ldapAuth = new LdapAuthenticationToken(auth, "ROLE_USER");
               
InitialLdapContext ldapContext = (InitialLdapContext) authAdapter
                               
.getObjectAttribute("ldapContext");
               
if (ldapContext != null) {
                        ldapAuth
.setContext(ldapContext);
               
}

               
return ldapAuth;
       
}

       
public boolean supports(Class clazz) {
               
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(clazz));
       
}

       
public LdapAuthenticator getAuthenticator() {
               
return authenticator;
       
}

       
public void setAuthenticator(LdapAuthenticator authenticator) {
               
this.authenticator = authenticator;
       
}
}
[LdapAuthenticatorImpl.java]
/**
 * Custom Spring Security LDAP authenticator which tries to bind to an LDAP server using the
 * passed-in credentials; does <strong>not</strong> require "master" credentials for an
 * initial bind prior to searching for the passed-in username.
 *
 * @author Jason
 */

public class LdapAuthenticatorImpl implements LdapAuthenticator {

       
private DefaultSpringSecurityContextSource contextFactory;
       
private String principalPrefix = "";

       
public DirContextOperations authenticate(Authentication authentication) {

               
// Grab the username and password out of the authentication object.
               
String principal = principalPrefix + authentication.getName();
               
String password = "";
               
if (authentication.getCredentials() != null) {
                        password
= authentication.getCredentials().toString();
               
}

               
// If we have a valid username and password, try to authenticate.
               
if (!("".equals(principal.trim())) && !("".equals(password.trim()))) {
                       
InitialLdapContext ldapContext = (InitialLdapContext) contextFactory
                                       
.getReadWriteContext(principal, password);

                       
// We need to pass the context back out, so that the auth provider can add it to the
                       
// Authentication object.
                       
DirContextOperations authAdapter = new DirContextAdapter();
                        authAdapter
.addAttributeValue("ldapContext", ldapContext);

                       
return authAdapter;
               
} else {
                       
throw new BadCredentialsException("Blank username and/or password!");
               
}
       
}

       
/**
         * Since the InitialLdapContext that's stored as a property of an LdapAuthenticationToken is
         * transient (because it isn't Serializable), we need some way to recreate the
         * InitialLdapContext if it's null (e.g., if the LdapAuthenticationToken has been serialized
         * and deserialized). This is that mechanism.
         *
         * @param authenticator
         *          the LdapAuthenticator instance from your application's context
         * @param auth
         *          the LdapAuthenticationToken in which to recreate the InitialLdapContext
         * @return
         */

       
static public InitialLdapContext recreateLdapContext(LdapAuthenticator authenticator,
                       
LdapAuthenticationToken auth) {
               
DirContextOperations authAdapter = authenticator.authenticate(auth);
               
InitialLdapContext context = (InitialLdapContext) authAdapter
                               
.getObjectAttribute("ldapContext");
                auth
.setContext(context);
               
return context;
       
}

       
public DefaultSpringSecurityContextSource getContextFactory() {
               
return contextFactory;
       
}

       
/**
         * Set the context factory to use for generating a new LDAP context.
         *
         * @param contextFactory
         */

       
public void setContextFactory(DefaultSpringSecurityContextSource contextFactory) {
               
this.contextFactory = contextFactory;
       
}

       
public String getPrincipalPrefix() {
               
return principalPrefix;
       
}

       
/**
         * Set the string to be prepended to all principal names prior to attempting authentication
         * against the LDAP server.  (For example, if the Active Directory wants the domain-name-plus
         * backslash prepended, use this.)
         *
         * @param principalPrefix
         */

       
public void setPrincipalPrefix(String principalPrefix) {
               
if (principalPrefix != null) {
                       
this.principalPrefix = principalPrefix;
               
} else {
                       
this.principalPrefix = "";
               
}
       
}

}

[LdapAuthenticationToken.java]
/**
 * <p>
 * Authentication token to use when an app needs further access to the LDAP context used to
 * authenticate the user.
 * </p>
 *
 * <p>
 * When this is the Authentication object stored in the Spring Security context, an application
 * can retrieve the current LDAP context thusly:
 * </p>
 *
 * <pre>
 * LdapAuthenticationToken ldapAuth = (LdapAuthenticationToken) SecurityContextHolder
 *              .getContext().getAuthentication();
 * InitialLdapContext ldapContext = ldapAuth.getContext();
 * </pre>
 *
 * @author Jason
 *
 */

public class LdapAuthenticationToken extends AbstractAuthenticationToken {

       
private static final long serialVersionUID = -5040340622950665401L;

       
private Authentication auth;
       
transient private InitialLdapContext context;
       
private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

       
/**
         * Construct a new LdapAuthenticationToken, using an existing Authentication object and
         * granting all users a default authority.
         *
         * @param auth
         * @param defaultAuthority
         */

       
public LdapAuthenticationToken(Authentication auth, GrantedAuthority defaultAuthority) {
               
this.auth = auth;
               
if (auth.getAuthorities() != null) {
                       
this.authorities.addAll(Arrays.asList(auth.getAuthorities()));
               
}
               
if (defaultAuthority != null) {
                       
this.authorities.add(defaultAuthority);
               
}
               
super.setAuthenticated(true);
       
}

       
/**
         * Construct a new LdapAuthenticationToken, using an existing Authentication object and
         * granting all users a default authority.
         *
         * @param auth
         * @param defaultAuthority
         */

       
public LdapAuthenticationToken(Authentication auth, String defaultAuthority) {
               
this(auth, new GrantedAuthorityImpl(defaultAuthority));
       
}

       
public GrantedAuthority[] getAuthorities() {
               
GrantedAuthority[] authoritiesArray = this.authorities.toArray(new GrantedAuthority[0]);
               
return authoritiesArray;
       
}

       
public void addAuthority(GrantedAuthority authority) {
               
this.authorities.add(authority);
       
}

       
public Object getCredentials() {
               
return auth.getCredentials();
       
}

       
public Object getPrincipal() {
               
return auth.getPrincipal();
       
}

       
/**
         * Retrieve the LDAP context attached to this user's authentication object.
         *
         * @return the LDAP context
         */

       
public InitialLdapContext getContext() {
               
return context;
       
}

       
/**
         * Attach an LDAP context to this user's authentication object.
         *
         * @param context
         *          the LDAP context
         */

       
public void setContext(InitialLdapContext context) {
               
this.context = context;
       
}

}


'개발자세상' 카테고리의 다른 글

박대연, 그리고 안철수  (1) 2009.09.24
LDAP Query  (0) 2009.09.08
Spring Security 와 Active Directory 연동  (0) 2009.09.01
UML 2.0 과 유스케이스 강의를 듣고  (0) 2009.08.28
RPM 관련 명령  (0) 2009.08.18
Posted by headiron
,

B3 관련하여 본사 AD와 연동을 위해 Spring Security와 AD연동을 테스트 해 보았다.

아래와 같이 spring 설정을 하게 되면 Spring Security는 잘 동작 한다.

이 경우 인증 뿐만 아니라 AD의 그룹기능을 이용하여 Spring Security의 Role도 연동할 수 있게 된다. ( DefaultLdapAuthoritiesPopulator class의 "rolePrefix" 부분을 설정하면 AD의 그룹명 앞에 Prefix를 붙여서 작업할 수 있다. )

하지만 이 경우의 문제점은 AD의 관리자 권한을 가지고 있어야만 된다는 것이다.

여러 모로 생각해 보아도 우리에게 AD 관리자 권한을 열어 줄리는 만무한데...-.-

아래 내용은 http://maniezhilan.blogspot.com/2008/10/spring-security-204-with-active.html 에서 퍼왔음.

[applicationContext-security.xml]
 
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:s="http://www.springframework.org/schema/security"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
 http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
 <s:http>
         <s:intercept-url pattern="/secure/extreme/**" access="ROLE_eCommunications"/>
         <s:intercept-url pattern="/secure/**" access="IS_AUTHENTICATED_REMEMBERED"/>
         <s:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
         <s:form-login/>
         <s:anonymous/>
         <s:logout/>
 </s:http>
 <bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
  <constructor-arg value="ldap://192.168.192.71:3268/DC=dev,DC=247realmedia,DC=co,DC=kr?sAMAccountName?sub?(objectClass=*)"/>
  <property name="userDn" value="CN=kim ducheol,CN=Users,DC=dev,DC=247realmedia,DC=co,DC=kr"/>
  <property name="password" value="XXXXXXX"/>
 </bean>
 <bean id="secondLdapProvider" class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
  <s:custom-authentication-provider />
  <constructor-arg>
   <bean class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
    <constructor-arg ref="contextSource"/>
    <property name="userSearch">
     <bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
      <constructor-arg index="0" value=""/>
      <constructor-arg index="1" value="(&amp;(sAMAccountName={0})(objectclass=user))"/>
      <constructor-arg index="2" ref="contextSource" />
     </bean>    
    </property>
   </bean>
  </constructor-arg>
  <constructor-arg>
   <bean class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator">
    <constructor-arg ref="contextSource" />
    <constructor-arg value="" />
    <property name="rolePrefix" value="ROLE_"/>
    <property name="searchSubtree" value="true"/>
    <property name="convertToUpperCase" value="false"/>
   </bean>
  </constructor-arg>
 </bean>
</beans>

'개발자세상' 카테고리의 다른 글

LDAP Query  (0) 2009.09.08
Spring Security 와 Active Directory 연동 -2  (0) 2009.09.01
UML 2.0 과 유스케이스 강의를 듣고  (0) 2009.08.28
RPM 관련 명령  (0) 2009.08.18
kernel ARG_MAX 값  (0) 2009.05.08
Posted by headiron
,
시네큐브가 문을 닫는다는 메일을 보고 화들짝 놀라 일욜날 "디스이지 잉글랜드"를 보러 갔다.

나름 괜찮은 시설 및 공간을 가지고 있는 영화관을 왜 닫을 까 생각을 하며 예전에 호젓했던 푸드코드를 없애 버리고 패밀리 레스토랑으로 영화관 앞을 갑갑하게 만든 건물주가 영화관도 없애는거 아닌가 했더니 태광그룹이 직접 영화관을 운영하려고 운영사인 백두대간을 밀어 낸것이었다.

제일 좋아하는 상영관이 없어지는 줄 알고 놀란 가슴은 쓸어 내리기는 했지만 거대자본기업의 횡포에 속수무책할 수 밖에 없는 예술인들의 비애가 느껴졌다.

"디스이지 잉글랜드" 영화를 보고 처음에는 왜 이 영화였을까 하는 생각도 들었지만
한편으론 광기에 사로잡힌 "헤드스킨" 족에 맹족적으로 따라 다닌 주인공 "숀"의 모습에서
보수를 외치며 자신들의 기득권만 지키려는 보수세력에 박수부대 역활을 하고 있는 우리 나라 노인들이 오버랩 되버리는 건 혹시 나만의 생각일까?

갠적으로 "굿바이 큐브 웰컴 투 모모" 이벤트에서 제일 기대했던것이 35mm 영화 필름을 가져가는 행사였는데 영화 끝나고 보니 다들 필름속에서 자신들이 좋아 했던 장면을 찾느라 난리였다.

'타인의 취향"등이 었는데 나는 보지 못한 영화로 장면을 고를 수 없어 아쉬웠는데 정말 내가 좋아 했던 장면이었다면 아마 장난 아니었을 듯..
( 혹시 닥터 지바고에서 오마샤리프가 "라라"를 외치며 쓰러 지는 고를 수 있었다면 정말 좋았을 텐데..)
영화사 입장에서는 이사짐을 줄이기 위한 고육지책이었겠지만
관객들에게는 정말 소중한 추억을 주는 좋은 기획이었던것 같다.

어쨋든 시네큐브는 살아 있어 다행이지만
예전의 그 느낌이 계속 남아 있을 지 모르겠다.

이젠 "모모"로 가야 하나..

그나저나 이번 주말에는 "타인의 향기"를 함 보러 가볼까.

'사는이야기 > 영화이야기' 카테고리의 다른 글

타인이 취향  (0) 2009.09.16
[영화] 타인의 삶  (0) 2009.09.05
벤자민 버튼의 시간의 거꾸로 간다.  (0) 2009.02.22
발키리를 보고.  (0) 2009.02.01
I have a dream, a song to sing  (0) 2008.12.09
Posted by headiron
,
대학교 때 잠깐 들었던 UML 강의 하나로 근 10년을 버티려니 힘들다 싶어 강의를 신청하고 들었는데,
참 잘 했다는 생각이 든다.

학교 때 배웠던 UML Notation 같은 부분은 거의 유사 했으나 이를 작성해나가는 개발 방법론에서는 정말 많은 내용을 배울 수 있는 자리였다.

생각해보면 학교 졸업할 때 Java 언어가 1.2 정도에서 지금은 6.0 으로 갔는데 개발 방법론은 예전 그래도 라고하면 말이 안되기는 하다.

사실 회사에서는 Agile 방법론에 따른 개발을 진행하고 Global Project는 대부분의 업무 분석을 정팀장님이 하는 상황이고 보면 해당 강좌가 나아게 업무적인 도움이 될지는 조금 미지수 이기는 하다.

하지만 언제까지 코딩만 할 수 없는 것이고 내 스스로가 직위가 상승해 가면 그에 따른 프로젝트 운영 능력을 키워가려면 큰 도움이 된다고 생각한다.

요즘에는 각종 Framework이나 개발 관련 Issue를 따라 가다 보니 방법론 쪽엔 좀 등한시 하는 경향이 있었는데

그런 나에게 좋은 자극이 되는 그런 강의 였었던것 같다.

근데... 앞으로 2주동안 또 강의를 들어야 하는데 그건 또 어떻게 들을지...-.-

'개발자세상' 카테고리의 다른 글

Spring Security 와 Active Directory 연동 -2  (0) 2009.09.01
Spring Security 와 Active Directory 연동  (0) 2009.09.01
RPM 관련 명령  (0) 2009.08.18
kernel ARG_MAX 값  (0) 2009.05.08
Oracle , Sun 인수  (0) 2009.04.22
Posted by headiron
,

RPM 관련 명령

개발자세상 2009. 8. 18. 15:57
RPM 파일 리스트 보는 명령
shell>> rpm -pql <rpm파일명>

RPM 파일 압축을 푸는 명령
shell>> rpm2cpio <rpm파일명> | cpio -ivd

'개발자세상' 카테고리의 다른 글

Spring Security 와 Active Directory 연동  (0) 2009.09.01
UML 2.0 과 유스케이스 강의를 듣고  (0) 2009.08.28
kernel ARG_MAX 값  (0) 2009.05.08
Oracle , Sun 인수  (0) 2009.04.22
ZK 사용기  (0) 2009.04.05
Posted by headiron
,
준비가 안된 종주여서 인지 실패하고 말았다.

사실 몸상태는 작년 때 보다 훨씬 좋았는데,

연하천을 가는 도중에 무릎쪽에서 조금씩 통증이 와서 연하천을 지나 음정마을로 내려와 버렸다.

실패한 원인을 생각해보면

1. 준비가 될 된것이 제일 큰 원인인것 같다.
   첫날 노고단 대피소에 갔더니 예약이 꽉 찼다고 한다.
   인월에서 올라가는 계획을 세우다가 날씨가 문제가 되고 해서 정확안 일정을 잡지 못한 상태에서 무작정 출발 해서 보니 대피소는 전혀 예약을 못했다.그래도 노고단은 예약 안 됐을 줄 알았는데..-.-
   다른 산장은 별 문제 없겠지만 노고단은 등산로 초입에 있는 대피소라 빈 자리가 나기를 바라기도 힘들듯 하여 구례로 내려와서 여관에서 잤더니 문제가 됐다.
   아침 4시 버스를 타려고 참을 청했지만 잠도 안오고 너무 무리 될 듯 하여 6시 버스를 탔는데 어떻게든 세석 까지 갈려다 보니 무릎에 무리가 좀 온것 같다.
   다음에는 일단 산장 예약은 미리 챙겨야 할 듯 하다.

2. 운동 부족
   사실 일정이 뒤틀리면서 문제가 되긴 했지만 제일 큰 문제 중 하나는 내 스스로의 체력이 부족했던것 같다.
   사실 연하천까지 가는 도중에 거의 쉬지 않고 가면서 평균 소요시간을 시간당 10~15분 정도를 세이브 하고 있었는데 몸 상태가 좋다고 생각만 했는데 사실 체력적인 부분에서 문제가 있었던듯 하다.
  무릎에 통증이 살짝 왔었던 것도 무릎이 내 몸무게와 배낭 부게를 이기지 못했기 떄문이리라.

3. 수면 부족
  사실 이 부분은 제일 문제가 적었지만. 여관에서 잠을 청하는데 도무지 잠이 오질 안 았다.
  맥주도 마셔 보고 했는데 새벽 까지 잠이 안왔다. 결국 3시간 정도를 자고 오르게 됐는데 일찍 잠들었다면 4시 버스를 타고 출발하여 무리할 일은 없었을 것 같다.
  담에는 구할 수 있으면 수면제라도 하나를 준비해 가야 할 듯하다.


뭐... 실패는 아쉽지만 그래도 소득은 있었다.

일단 구례에서 하루 자면서 구례 일대에 24시간 편의점 , 24시간 식당 , 숙박 시설 등을 보게 됐다.
잠은 신흥관에서 잤는데 거긴 여관과 목용탕을 함께 해서 여관 사용자들한테는 목욕탕도 무료 였다.
시설은 좀 낡았지만, 나중에 구례로 내려온때는 머물만한 숙박지 였다.
뭐... 금액도 쌌고.^^ ( 다른데는 3만5천원에 현금 일 경우 3만원 까지 얘기를 해 줬는데 여기는 현금 2만 5천원으로 ^^ )

그리고 처음으로 총각샘의 위치를 알게 됐다.
작년에 연하천 가는 도중에 물이 부족해서 고생 했고 , 그래서 이번에는 최대한 물을 마시지 않고 등반 했는데.종주를 140번 가량 하셨다는 분 께서 알려 주셨다.
연하천 가는 도중에 철제 난관이 시작되는 큰 암석(?) 이 있는 곳에서 20m 정도 등반로를 벗어 나면 있었다.
( 예전 기억에도 그 지역에서 취사를 하는 사람을 봤던 기억이 난다.^^ )

글구 인월에서 어탕국수를 먹어 보았다.^^
뭐... 추어탕 비슷한 맛이고 실제 재료만 다를 뿐 맛이나 요리 하는 방식도 비슷한듯 했다.


일단은 언젠가 다시 종주를 하겠지만 우선은 지역 단위로 다녀볼 생각이다.

우선 9월달에 은 인월 -> 노고단 혹은 노고단-> 인월 방면 으로 한번,
그 후에 칠선 계곡으로 한번 올라 가볼 생각이고

올해 안에 몸을 좀 만들어서
내년 5월 중순 경에 세석 산장에 진달래 필때를 맞춰서 다시 한번 종주를 해볼 생각이다

'사는이야기 > 등반정보' 카테고리의 다른 글

오대산 소금강 등반 사진  (0) 2009.12.01
우이령 고개 등반기  (0) 2009.09.08
한라산 백록담 정상  (0) 2009.05.27
한라산 등반사진  (0) 2009.05.26
백운대에 올라...  (0) 2009.05.09
Posted by headiron
,
동굴이 길고 크긴 한데..

그닥 볼것은..

오히려 예전에 동해시에 있는 천곡동굴이 아기자기하게 꾸며서 재미있었는데..



'사진,여행 > 제주도워크샵' 카테고리의 다른 글

숙소 앞에서...  (0) 2009.06.25
중문해수욕장  (0) 2009.06.25
Z4 비틀  (0) 2009.06.25
어승생악...  (0) 2009.06.25
송악산 해변 해안 동굴  (0) 2009.06.25
Posted by headiron
,

한경면 두모리 1888 번지 ... 숙소 이름은 생각 안 나네...-.-

황부장님과 연이 있으신 분들이 운영하는 곳이라...

나름 사람 없어 한적하고 좋았다.

바닷가랑도 가깝기는 한데 바로 보이지 않는 다는 아쉬움이..-.-

'사진,여행 > 제주도워크샵' 카테고리의 다른 글

만장굴...  (0) 2009.06.25
중문해수욕장  (0) 2009.06.25
Z4 비틀  (0) 2009.06.25
어승생악...  (0) 2009.06.25
송악산 해변 해안 동굴  (0) 2009.06.25
Posted by headiron
,

여사원들 빠뜨리느라 신났는데

난.... 등산화를 신은 바람에.... 얌전했었다는...

학교다닐때는 내가 앞장 섰었는데..-.-

'사진,여행 > 제주도워크샵' 카테고리의 다른 글

만장굴...  (0) 2009.06.25
숙소 앞에서...  (0) 2009.06.25
Z4 비틀  (0) 2009.06.25
어승생악...  (0) 2009.06.25
송악산 해변 해안 동굴  (0) 2009.06.25
Posted by headiron
,

제주도에서 렌트했었던 Z4와 비틀...

Z4... 장난아니게 속도감이 나긴 했는데 .. 솔직히 좀 무서웠다...=-.-

'사진,여행 > 제주도워크샵' 카테고리의 다른 글

숙소 앞에서...  (0) 2009.06.25
중문해수욕장  (0) 2009.06.25
어승생악...  (0) 2009.06.25
송악산 해변 해안 동굴  (0) 2009.06.25
송악산  (0) 2009.06.25
Posted by headiron
,