We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/OhSeongRak/meeting-room-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
# -*- coding: utf-8 -*-
"""
SSO 로그인 관리 모듈
포털 로그인 후 SSO 토큰을 통해 회의실 시스템에 접근하고
세션 쿠키를 관리합니다.
"""
import time
import re
import logging
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
logger = logging.getLogger(__name__)
class LoginManager:
"""SSO 로그인 관리 클래스"""
def __init__(self, config):
"""
Args:
config: 설정 모듈 (config.py)
"""
self.config = config
self.session_cookies = {}
def login(self):
"""
전체 로그인 프로세스 실행
Returns:
dict: 세션 쿠키 딕셔너리
Raises:
Exception: 로그인 실패 시
"""
logger.info("자동 로그인 시작...")
driver = self._init_driver()
try:
# 1. 포털 로그인
self._login_to_portal(driver)
# 2. SSO 토큰으로 회의실 시스템 접근
self._access_meeting_room_system(driver)
# 3. 쿠키 수집
self._collect_cookies(driver)
logger.info("로그인 완료!")
return self.session_cookies
except Exception as e:
logger.error(f"로그인 실패: {str(e)}", exc_info=True)
raise
finally:
driver.quit()
def _init_driver(self):
"""Chrome 드라이버 초기화"""
options = webdriver.ChromeOptions()
options.add_argument('--start-maximized')
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
service = Service(self.config.CHROMEDRIVER_PATH)
return webdriver.Chrome(service=service, options=options)
def _login_to_portal(self, driver):
"""포털 로그인"""
logger.info("회사 포털 접속 중...")
driver.get(self.config.PORTAL_URL)
time.sleep(3)
logger.info("로그인 폼 입력 중...")
wait = WebDriverWait(driver, 10)
user_id_field = wait.until(EC.presence_of_element_located((By.ID, "userId")))
user_pwd_field = driver.find_element(By.ID, "userPwd")
login_button = driver.find_element(By.ID, "login_area")
user_id_field.send_keys(self.config.USER_ID)
user_pwd_field.send_keys(self.config.USER_PASSWORD)
login_button.click()
logger.info("로그인 처리 중...")
time.sleep(5)
def _access_meeting_room_system(self, driver):
"""SSO를 통한 회의실 시스템 접근"""
# 방법 1: SSO 토큰 추출
if self._try_sso_token_method(driver):
return
# 방법 2: 버튼 클릭
if self._try_button_click_method(driver):
return
raise Exception("회의실 시스템 접근 실패")
def _try_sso_token_method(self, driver):
"""SSO 토큰 추출 방식"""
logger.info("SSO 토큰 추출 시도...")
page_source = driver.page_source
pattern = r"https://srs\.ktds\.co\.kr:8443/front/ssoLoginRoom\.do\?.*?sso_token=([^'\"]+)"
matches = re.findall(pattern, page_source)
if matches:
sso_token = matches[0]
logger.info(f"SSO 토큰 발견: {sso_token[:50]}...")
sso_url = f"https://srs.ktds.co.kr:8443/front/ssoLoginRoom.do?sso_token={sso_token}"
driver.get(sso_url)
time.sleep(5)
logger.info(f"회의실 시스템 접속 완료: {driver.current_url}")
return True
logger.warning("SSO 토큰을 찾지 못함")
return False
def _try_button_click_method(self, driver):
"""회의실 버튼 클릭 방식"""
logger.info("회의실 버튼 클릭 방식 시도...")
try:
meeting_button = self._find_meeting_button(driver)
if meeting_button:
logger.info("회의실 버튼 클릭...")
meeting_button.click()
time.sleep(3)
# 새 창 처리
if len(driver.window_handles) > 1:
driver.switch_to.window(driver.window_handles[-1])
time.sleep(2)
logger.info(f"회의실 시스템 접속 완료: {driver.current_url}")
return True
except Exception as e:
logger.error(f"버튼 클릭 실패: {str(e)}")
return False
def _find_meeting_button(self, driver):
"""회의실 버튼 찾기 (여러 방법 시도)"""
# 방법 1: ID로 찾기
try:
return driver.find_element(By.ID, "_qmytodo_INSTANCE__for_personal_a_100474891")
except:
pass
# 방법 2: 텍스트로 찾기
try:
links = driver.find_elements(By.TAG_NAME, "a")
for link in links:
if "회의실 예약" in link.text or "회의실" in link.text:
return link
except:
pass
# 방법 3: onclick 속성으로 찾기
try:
elements = driver.find_elements(By.XPATH, "//*[@onclick]")
for elem in elements:
onclick = elem.get_attribute("onclick")
if "ssoLoginRoom" in onclick:
return elem
except:
pass
return None
def _collect_cookies(self, driver):
"""쿠키 수집"""
cookies = driver.get_cookies()
logger.info(f"총 {len(cookies)}개의 쿠키 발견")
for cookie in cookies:
self.session_cookies[cookie['name']] = cookie['value']
logger.debug(f"쿠키: {cookie['name']}")
if cookie['name'] == 'SESSION':
logger.info(f"SESSION 쿠키 획득: {cookie['value'][:20]}...")
if 'SESSION' not in self.session_cookies:
raise Exception("SESSION 쿠키를 찾을 수 없습니다.")
def get_headers(self):
"""
API 요청용 헤더 생성
Returns:
dict: HTTP 헤더
Raises:
Exception: 로그인되지 않은 경우
"""
if not self.session_cookies:
raise Exception("로그인이 필요합니다. login()을 먼저 호출하세요.")
cookie_str = '; '.join([f"{k}={v}" for k, v in self.session_cookies.items()])
return {
'Cookie': cookie_str,
'Content-Type': 'application/json;charset=UTF-8',
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
'Referer': f'{self.config.BASE_URL}/front/allFloorsMeeting.do',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}